Skip to content

feat(training-agent): add cursor pagination to list_content_standards, list_collection_lists, list_property_lists#3147

Merged
bokelley merged 2 commits into
mainfrom
claude/issue-3112-governance-pagination
Apr 25, 2026
Merged

feat(training-agent): add cursor pagination to list_content_standards, list_collection_lists, list_property_lists#3147
bokelley merged 2 commits into
mainfrom
claude/issue-3112-governance-pagination

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

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 pagination block (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 handleListAccounts pattern exactly:

  • handleListContentStandards (content-standards-handlers.ts:229) — reads req.pagination?.max_results (default 50, cap 100), decodes cursor via decodeOffsetCursor('content_standards', ...), slices the filtered result set, emits full pagination envelope.
  • 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 updatespagination property added to all three MCP tool definitions (JSON inputSchema) and to LIST_COLLECTION_LISTS_SCHEMA in framework-server.ts (Zod-validated path for list_collection_lists).

Storyboards — three new universal storyboards, each bootstrapping 3 items via real create_* calls and walking two pages with max_results=2:

  • static/compliance/source/universal/content-standards-pagination-integrity.yaml
  • static/compliance/source/universal/collection-lists-pagination-integrity.yaml
  • static/compliance/source/universal/property-lists-pagination-integrity.yaml

Doc-paritydocs/building/conformance.mdx and docs/building/compliance-catalog.mdx updated with rows for all three new storyboards.

Non-breaking justification

Adds pagination as an optional output field to handlers that previously returned none or a stub. No existing fields renamed, removed, or made required. Consumers that omit pagination input receive identical results to before (offset=0, maxResults=50, all items on one page, has_more: false). --empty changeset — training-agent server-side behavior only, no protocol schema change.

Nit surfaced in pre-PR review (not fixed here)

list_collection_lists tool uses taskSupport: 'optional' while list_content_standards and list_property_lists use 'forbidden' — pre-existing inconsistency, unrelated to pagination. Worth a follow-up.

Pre-PR review

  • code-reviewer: approved — no blockers. Noted Zod asymmetry between customToolFor and adapt() paths (non-blocking: decodeOffsetCursor try/catch already handles malformed cursors safely on the adapt path). Noted confusing variable ordering around totalMatching (cosmetic).
  • ad-tech-protocol-expert: approved — non-breaking per spec. Confirmed INVALID_REQUEST is the correct error code for malformed cursors (consistent with all five prior paginated handlers). No protocol concerns with replacing the has_more: false stub.

Session: https://claude.ai/code/session_018AkoeaWmnrsnbXBtK8FLD2


Generated by Claude Code

…rs (#3112)

Adds cursor-based pagination to list_content_standards, list_collection_lists,
and list_property_lists — the fifth batch in the rolling pagination conformance
series (#3095, #3100, #3109, #3110).

https://claude.ai/code/session_018AkoeaWmnrsnbXBtK8FLD2
…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>
@bokelley bokelley marked this pull request as ready for review April 25, 2026 15:34
@bokelley bokelley merged commit 28956dd into main Apr 25, 2026
19 checks passed
@bokelley bokelley deleted the claude/issue-3112-governance-pagination branch April 25, 2026 15:37
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>
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.

Pagination integrity for governance lists (list_content_standards, list_collection_lists, list_property_lists)

2 participants