feat(training-agent): add cursor pagination to list_content_standards, list_collection_lists, list_property_lists#3147
Merged
Conversation
…governance pagination storyboards Triage's #3147 hit two build-time lints CI surfaced: 1. **Storyboard scoping** — 15 sample_request blocks (3 storyboards × 5 steps each, minus capability_discovery) omitted brand/account identity. The create_* and list_* tasks for governance lists are tenant-scoped per `lint-storyboard-scoping`. Adds the canonical `account: { brand: { domain: 'acmeoutdoor.example' }, operator: 'pinnacle-agency.example' }` to all 15. 2. **Idempotency_key on mutating setup steps** — 9 create_* sample_requests (3 per storyboard) on `create_collection_list`/`create_content_standards`/ `create_property_list` omitted `idempotency_key`, which their request schemas mark as required. Adds `$generate:uuid_v4#<storyboard>_setup_<step>` per the established convention. 3. **Invalid channel value** — `create_standards_2` used `channels_any: ["video"]` which isn't in the channels enum. Replace with `["olv"]` (the standardized value for online video advertising outside CTV per `static/schemas/source/enums/channels.json`). Verified: 8/8 pagination storyboards pass against the training agent (list_creatives, get_signals, list_creative_formats, list_accounts, get_media_buys, content_standards, collection_lists, property_lists) — 41/41 steps clean. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced Apr 25, 2026
bokelley
pushed a commit
that referenced
this pull request
Apr 27, 2026
…rror steps (#2824) Distinguishes schema_invalid (payload intentionally malformed — skip lint, the default) from business_rule (schema-valid payload rejected for semantic reasons — validate sample_request anyway) on storyboard negative-path steps. Changes: - Update isNegativeStep() in lint-storyboard-sample-request-schema.cjs to branch on negative_path: business_rule before short-circuiting - Document expect_error, negative_path, sample_request_skip_schema in static/compliance/source/universal/storyboard-schema.yaml - Tag all 32 expect_error: true steps in the corpus (26 business_rule, 6 schema_invalid) - Fix fixture drift exposed by business_rule validation: add missing idempotency_key to 6 steps, fix signal destinations type field, and convert content-standards policy→policies array (pre-existing drift from PR #3147) - Add isNegativeStep negative_path branch test to test file https://claude.ai/code/session_019dMkCmDw5ro7hzMQ6iTkKQ
bokelley
added a commit
that referenced
this pull request
Apr 27, 2026
…#2824) (#3226) * feat(storyboard-lint): introduce negative_path attribute for expect_error steps (#2824) Distinguishes schema_invalid (payload intentionally malformed — skip lint, the default) from business_rule (schema-valid payload rejected for semantic reasons — validate sample_request anyway) on storyboard negative-path steps. Changes: - Update isNegativeStep() in lint-storyboard-sample-request-schema.cjs to branch on negative_path: business_rule before short-circuiting - Document expect_error, negative_path, sample_request_skip_schema in static/compliance/source/universal/storyboard-schema.yaml - Tag all 32 expect_error: true steps in the corpus (26 business_rule, 6 schema_invalid) - Fix fixture drift exposed by business_rule validation: add missing idempotency_key to 6 steps, fix signal destinations type field, and convert content-standards policy→policies array (pre-existing drift from PR #3147) - Add isNegativeStep negative_path branch test to test file https://claude.ai/code/session_019dMkCmDw5ro7hzMQ6iTkKQ * fix(storyboard-lint): rename business_rule→payload_well_formed, add governance check for activate_signal Addresses two issues from @bokelley's review of #3226: 1. Renames negative_path value business_rule → payload_well_formed across the entire corpus (26 storyboard steps, lint predicate, storyboard-schema.yaml doc, and test assertions). The new name is broader — auth failures, state conflicts, and governance denials all share the same lint behavior (validate the payload; expect runtime rejection), so the name should describe the payload shape, not the rejection class. 2. Fixes the CI failure on activate_signal_denied: adds governance checking to handleActivateSignal in the training agent (mirrors create_media_buy — if governance plans exist in the session and no governance_context is provided, return GOVERNANCE_DENIED). The signal_marketplace/governance_denied storyboard sets up a $100 plan via sync_plans before calling activate_signal, so the new guard fires correctly. 3. Adds sample_response fixture to activate_signal_denied documenting the expected GOVERNANCE_DENIED error shape. https://claude.ai/code/session_012hzHajMZVRBvPxrs4ogn9U --------- Co-authored-by: Claude <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #3112
Fifth entry in the rolling pagination conformance series (#3095, #3100, #3109, #3110). Adds full cursor-based pagination to the three governance list handlers that previously emitted no
paginationblock (list_content_standards,list_property_lists) or a non-functional stub (list_collection_lists). Also ships three new universal compliance storyboards and the required doc-parity rows.Changes
Handler fixes — mirrors
handleListAccountspattern exactly:handleListContentStandards(content-standards-handlers.ts:229) — readsreq.pagination?.max_results(default 50, cap 100), decodes cursor viadecodeOffsetCursor('content_standards', ...), slices the filtered result set, emits fullpaginationenvelope.handleListCollectionLists(inventory-governance-handlers.ts:235) — replaces{ has_more: false }stub with real offset-cursor implementation, kind'collection_lists'.handleListPropertyLists(property-handlers.ts:241) — same pattern, kind'property_lists'.inputSchema updates —
paginationproperty added to all three MCP tool definitions (JSON inputSchema) and toLIST_COLLECTION_LISTS_SCHEMAinframework-server.ts(Zod-validated path forlist_collection_lists).Storyboards — three new universal storyboards, each bootstrapping 3 items via real
create_*calls and walking two pages withmax_results=2:static/compliance/source/universal/content-standards-pagination-integrity.yamlstatic/compliance/source/universal/collection-lists-pagination-integrity.yamlstatic/compliance/source/universal/property-lists-pagination-integrity.yamlDoc-parity —
docs/building/conformance.mdxanddocs/building/compliance-catalog.mdxupdated with rows for all three new storyboards.Non-breaking justification
Adds
paginationas an optional output field to handlers that previously returned none or a stub. No existing fields renamed, removed, or made required. Consumers that omitpaginationinput receive identical results to before (offset=0, maxResults=50, all items on one page,has_more: false).--emptychangeset — training-agent server-side behavior only, no protocol schema change.Nit surfaced in pre-PR review (not fixed here)
list_collection_liststool usestaskSupport: 'optional'whilelist_content_standardsandlist_property_listsuse'forbidden'— pre-existing inconsistency, unrelated to pagination. Worth a follow-up.Pre-PR review
customToolForandadapt()paths (non-blocking:decodeOffsetCursortry/catch already handles malformed cursors safely on the adapt path). Noted confusing variable ordering aroundtotalMatching(cosmetic).INVALID_REQUESTis the correct error code for malformed cursors (consistent with all five prior paginated handlers). No protocol concerns with replacing thehas_more: falsestub.Session: https://claude.ai/code/session_018AkoeaWmnrsnbXBtK8FLD2
Generated by Claude Code