Skip to content

docs: clarify inline creative handling (Option B)#789

Closed
bokelley wants to merge 59 commits intomainfrom
bokelley/creative-id-conflict
Closed

docs: clarify inline creative handling (Option B)#789
bokelley wants to merge 59 commits intomainfrom
bokelley/creative-id-conflict

Conversation

@bokelley
Copy link
Copy Markdown
Contributor

Summary

Clarifies the behavior for inline creatives in create_media_buy and update_media_buy based on Slack discussion with Marek:

  • Inline creatives array in media buy operations creates NEW creatives only
  • Submitting an existing creative_id returns CREATIVE_ID_EXISTS error
  • To update existing creatives, use sync_creatives (upsert semantics)
  • Creatives in active delivery cannot be updated via sync_creatives (CREATIVE_IN_ACTIVE_DELIVERY)

This aligns with industry standards (Meta, Google, LinkedIn APIs treat creatives as immutable after creation).

Test plan

  • All existing tests pass (schema validation, examples, etc.)
  • Marek to implement the error behavior in the sales agent

🤖 Generated with Claude Code

BaiyuScope3 and others added 27 commits January 2, 2026 14:34
- Add new 'assets' array to format schema with 'required' boolean per asset
- Deprecate 'assets_required' (still supported for backward compatibility)
- Enables full asset discovery for buyers and AI agents
- Update server to include both fields in format responses
- Update documentation across creative and media-buy docs
- Bump version to 2.6.0
- Resolve package-lock.json version to 2.6.0
- Accept main's simplified media-buy/list_creative_formats (points to creative docs)
- Update creative/list_creative_formats with assets field
- Fix asset_type: use 'url' for tracking pixels (valid content type)
…l-discovery

feat: Improve assets discovery
- Keep version 2.6.0
- Add docs versioning support from main
- Add sync workflow triggers for 2.6.x branch
feat: update all document schema reference to 2.6 schema for 2.6-rc
git diff only detects tracked files. Use git add + git diff --cached
to properly detect new v2.6-rc/ folder on first sync.
fix: detect untracked files in sync-versioned-docs workflow
Main branch is protected. Use peter-evans/create-pull-request action
to create a PR for the synced docs instead of direct push.
fix: create PR instead of pushing directly to main
Merged 32 commits from main including:
- Schema: Allow additional properties for forward compatibility (#646)
- Schema versioning: Replace symlinks with HTTP middleware (#644)
- Workflow: Add schema sync to versioned docs (#639)
- Addie: Home button fix, sidebar, thread flow improvements
- Admin: PostHog integration, activity feed, engagement scoring
- Slack: User mentions, leader names, channel fixes
- Members: Search, intro emails, founding badge
- Server: Company type validation, HTML entity parsing

Conflicts resolved:
- .github/workflows/sync-versioned-docs.yml: kept main version with schema sync
- package-lock.json: accepted main version
Rebuilds 2.6.0 schemas to include the relaxed validation from #646.
All schema objects now allow unknown fields for forward compatibility.
…o-2.6.x

chore: catch 2.6.x up with latest main updates
* feat: Add typed extensions infrastructure with auto-discovery

Typed extensions provide formal JSON schemas for vendor-agnostic
extension data in `ext.{namespace}` fields. This enables SDK code
generation, schema validation, and cross-vendor interoperability.

**New features:**
- Extension meta schema defining valid_from/valid_until version bounds
- Auto-discovery of extensions during schema build
- Version-filtered extension registries per schema version
- New `extensions_supported` field in agent card adcp extension
- Comprehensive test suite for extension infrastructure

**How it works:**
1. Extensions are defined in `/schemas/source/extensions/{namespace}.json`
2. Build script auto-discovers extensions and filters by version compatibility
3. Each versioned build includes only compatible extensions in registry
4. Agents declare supported extensions via `extensions_supported` array

This is a MINOR release adding new optional capabilities without
breaking existing functionality.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* docs: Fix A2A extension format and add MCP server card support

Updates documentation to be compliant with both protocol specs:

**A2A Agent Cards:**
- Changed from `extensions.adcp` object to proper A2A `extensions[]` array format
- Each extension now has uri, description, required, and params fields
- Extension URI: https://adcontextprotocol.org/extensions/adcp

**MCP Server Cards:**
- Added support for declaring AdCP via `_meta['adcontextprotocol.org']`
- Supports both `/.well-known/mcp.json` and `/.well-known/server.json`
- Uses reverse DNS namespacing per MCP server.json spec

**Extension Params Schema:**
- Updated description to clarify usage in both protocols
- Same params structure works for both A2A and MCP

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: Remove external $schema reference from MCP server card examples

The JSON schema validation test was failing because it tried to
validate against https://registry.modelcontextprotocol.io/server.schema.json
which is an external schema we don't have locally.

Removed the $schema field from MCP server card examples since they
reference an external MCP registry schema, not an AdCP schema.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: Add reserved namespaces and deprecation policy for extensions

Addresses PR review feedback:

**Reserved Namespaces (@BaiyuScope3)**
- Added RESERVED_NAMESPACES list: adcp, core, protocol, schema, meta, ext, context
- Build script now validates and rejects reserved namespaces
- Documented in extensions reference

**Deprecation Policy (@BaiyuScope3)**
- Added "Extension Deprecation Policy" section with:
  - When extensions may be deprecated (superseded, promoted, low adoption, incompatible)
  - Standard deprecation process (valid_until + 1 minor, CHANGELOG, migration guide)
  - Emergency deprecation for security issues

**Tests**
- Added test verifying reserved namespaces are not used

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* Add Property Governance Protocol for AdCP 3.0

This introduces a stateful property list management model for governance agents:

## Key Concepts

- **Property Lists**: Managed resources combining base property sets with dynamic filters
- **Feature Discovery**: Agents advertise scoring capabilities via `list_property_features`
- **Brand Manifests**: Buyers describe their brand identity; agents apply appropriate rules
- **Discriminated Unions**: `base_properties` uses `selection_type` discriminator for type safety

## Design Principles

- **Scores are internal**: Governance agents filter properties; raw scores never leave the agent
- **Setup-time, not bid-time**: Lists resolved during campaign planning, cached for real-time
- **Identifiers-only responses**: `get_property_list` returns identifiers, not full property objects
- **Notification webhooks**: Webhooks provide summary; recipients call `get_property_list` to refresh

## Schemas Added

- Property list CRUD operations (create, update, get, list, delete)
- Property list filters with explicit logic (`countries_all`, `channels_any`, `feature_requirements`)
- Feature requirements for quantitative (`min_value`/`max_value`) and categorical (`allowed_values`)
- Base property source with discriminated union (publisher_tags, publisher_ids, identifiers)
- Webhook notification schema
- Core identifier schema for reuse

## Documentation

- Governance Protocol overview
- Property Governance specification
- Task reference for all CRUD operations
- Brand Standards placeholder

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add changeset for Property Governance Protocol

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Use empty changeset for draft 3.0 proposal

No version bump needed for draft/proposal specs.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Address review feedback on Property Governance Protocol

Schema fixes:
- Add methodology_url (required) and methodology_version to property-feature-definition
- Add signature field (required) to webhook schema for security
- Make countries_all and channels_any required in property-list-filters
- Move auth_token from get_property_list to create_property_list response

Documentation fixes:
- Add terminology note: Orchestrator = Buyer Agent
- Update examples to show auth_token in create response only
- Add note that auth_token is only returned at creation time

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add validate_property_delivery task for post-campaign compliance validation

Introduces the "what I wanted vs what I got" validation concept:
- validate_property_delivery task validates delivery records against property lists
- Three statuses: compliant, non_compliant, unknown
- Unknown records are valid (detection gaps shouldn't penalize compliance)
- Compliance rate excludes unknown impressions from calculation
- Batch support up to 10,000 records per request

New schemas:
- delivery-record.json: Input record with identifier + impressions
- validation-result.json: Per-record validation result with status and violations
- validate-property-delivery-request.json: Request payload
- validate-property-delivery-response.json: Response with summary and per-record results

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add supply path authorization to validate_property_delivery

Extends validate_property_delivery to validate sales agent authorization:

- Add optional sales_agent_url to delivery records
- Check if sales agent is listed in publisher's adagents.json
- Return authorization status (authorized/unauthorized/unknown) per record
- Add authorization_summary with aggregate stats and authorization_rate
- Two independent checks: property compliance + supply path authorization

New schema:
- authorization-result.json: Per-record authorization validation result

Authorization uses same "unknown excludes from rate" pattern as property
compliance - you cannot penalize for detection gaps or unreachable files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Simplify validation response: raw counts + optional feature details

Changes:
- Remove compliance_rate and authorization_rate from response schemas
- Return raw counts only (1.2M verified, 0.8M unknown, 0.3M invalid)
- Consumers calculate rates as needed, excluding unknowns from denominator

- Add optional feature_id and requirement to violation objects
- For feature_failed violations, shows which feature and what threshold failed
- Helps debugging why a property was marked non-compliant

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Split unknown into unmodeled/unidentified, add optional aggregate metrics

- Split "unknown" status into two distinct statuses:
  - unmodeled: identifier recognized but agent has no data (e.g., property too new)
  - unidentified: identifier type not resolvable (e.g., detection failed)
- Add optional aggregate field for computed metrics:
  - score, grade, label fields for agent-specific measurements
  - methodology_url for transparency
- Update summary to track both unmodeled and unidentified separately
- Update documentation with new statuses and aggregate concept

Inspired by Scope3's inventory_coverage (modeled/unmodeled) pattern. The
distinction helps identify whether gaps are in data coverage vs identifier
resolution.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix include_compliant description to reference new statuses

Updated the description to list non_compliant, unmodeled, and unidentified
(instead of the old "unknown" status).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Move authorized-properties doc to Governance Protocol section

- Moved authorized-properties.mdx from media-buy/capability-discovery to
  governance/property (renamed to "Understanding Authorization")
- Added validate_property_delivery task to navigation
- Navigation now shows conceptual explainer before tech spec

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix broken links to authorized-properties after move

Updated links in media-buy docs to point to new location in
governance/property section.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add property_list filtering to get_products for 2.6.x

- Add optional property_list parameter to get_products request schema
- Add property_list_applied response field to indicate filtering status
- Update get_products docs with new parameter, response field, and usage example
- Mark changeset as minor for 2.6.x release

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add governance overview enhancements for working group alignment

- Change banner from Info to Warning for draft status
- Add mission statement for governance protocols
- Add Working Group Areas table mapping to protocol domains
- Add Prompt-Based Policies section for natural language policy support

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Fix broken links in v2.6-rc docs after authorized-properties move

Update links from /docs/media-buy/capability-discovery/adagents and
/docs/media-buy/capability-discovery/authorized-properties to their
new locations in /docs/governance/property/

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add get_property_features task and property_features discovery

- Add get_property_features task schemas for governance agents to return
  property certification/measurement data (carbon scores, TAG certified, etc.)
- Support two request modes: explicit property list or publisher discovery
- Add publisher_domain, property_types, property_tags filtering for discovery
- Add property_features field to adagents.json for feature provider discovery
- Rename from governance_agents to property_features for flexibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add filter semantics for geographic and channel compliance

Clarifies what "compliant in a country" means for property list filters:
- Refers to user location (where impressions are delivered)
- NOT publisher headquarters, server hosting, or incorporation country
- Requires regulatory compliance, ad delivery capability, and valid consent

Also clarifies channel filter semantics (technical capability, availability,
quality standards) and adds cross-references between docs and schema.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Revert filter semantics changes

The Filter Semantics section overstated the meaning of countries_all -
it's about whether the agent has feature data for properties in that
country, not about legal compliance.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Add if_not_covered handling and standardize on 'covered' terminology

- Add if_not_covered field to feature-requirement.json (exclude|include)
- Add coverage_gaps to get-property-list-response.json for transparency
- Change 'unmodeled' to 'not_covered' throughout for consistency:
  - validation-result.json status enum
  - validate-property-delivery-response.json summary fields
  - specification.mdx and validate_property_delivery.mdx documentation
- Document coverage handling in property_lists.mdx

This allows callers to specify how missing feature data should be handled
(strict vs lenient enforcement) and provides visibility into which
properties were included despite coverage gaps.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Clarify countries_all semantics: feature data, not compliance

Remove "compliant" language from countries_all descriptions to avoid
confusion with legal/regulatory compliance. The field means "property
must have feature data for these countries" - same semantics as content
standards PR 621 ("standards apply in these countries").

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Update 2.6.x with new changes
Includes:
- impressions field in package-request.json and update-media-buy-request.json
- paused field in package-request.json
- Other pending schema updates from 2.6.x source
…mas-with-impressions

chore: Fix/rebuild 2.6.0 schemas with impressions
Copy link
Copy Markdown

@marekjalovec marekjalovec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love this change, makes it easier to work with and understand what's going on.

bokelley and others added 22 commits January 16, 2026 08:59
Migration 153 incorrectly swept ALL perspectives with NULL working_group_id
into the Editorial working group, including RSS feed articles.

This migration sets working_group_id = NULL for all rss/email sourced content,
so it displays via The Latest sections through addie_knowledge instead of
on working group pages.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
…773)

* fix: align funnel metrics with analytics and prevent duplicate orgs

- Update dashboard funnel to use MEMBER_FILTER instead of deprecated
  org_lifecycle_stage field for consistent member counts
- Simplify HAS_USER and HAS_ENGAGED_USER filters to use organization_domains
  for Slack user matching (removes reliance on pending_organization_id and
  slack_activity_daily table)
- Add 409 Conflict checks to create-prospect endpoints to prevent duplicate
  organizations when domain is already claimed
- Add duplicate domain check before user org creation
- Add index on last_slack_activity_at for query performance

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: rename migration to 170 to avoid version conflict

Migration 169 already exists on main (remove_rss_from_editorial).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
#774)

* fix: remove RSS content from Editorial working group

Migration 153 incorrectly swept ALL perspectives with NULL working_group_id
into the Editorial working group, including RSS feed articles.

This migration sets working_group_id = NULL for all rss/email sourced content,
so it displays via The Latest sections through addie_knowledge instead of
on working group pages.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: add admin escalations page and configurable notification channel

- Add /admin/escalations page to view and manage Addie's escalations
- Add escalation channel setting to system settings page
- Update escalation tools to use configured channel from settings
- Add Escalations link to admin sidebar
- Add private channel validation for escalation channel

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- create_media_buy and update_media_buy creatives array creates NEW creatives only
- Add CREATIVE_ID_EXISTS error code when creative_id already exists in library
- Add CREATIVE_IN_ACTIVE_DELIVERY error code to sync_creatives
- Clarify that sync_creatives is the canonical way to update/delete creatives
- Document upsert semantics with active delivery protection

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove creative_ids from package-request.json and update-media-buy-request.json
- Use creative_assignments for assigning existing library creatives (supports optional weight/placement_ids)
- Update documentation and examples to use creative_assignments
- Clarify delete_missing in sync_creatives cannot delete creatives in active delivery

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: Add Zoom meeting webhooks and user timezone support

- Handle meeting.started/ended webhooks to update meeting status
- Handle recording.completed to store transcripts and Zoom AI summaries
- Send Slack notifications when meetings start/end
- Add user timezone column with migration
- Add helper functions for timezone management

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: Rename user_timezone migration to 171 to avoid conflict

Migration 170 already exists in main (slack_activity_index).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: Use empty changeset for server-only changes

Server implementation changes (webhooks, migrations) don't require
a protocol version bump.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Meeting scheduling timezone comparison bug

When Claude provides a datetime like "2026-01-15T09:15:00" without timezone
info, JavaScript's Date parses it as server local time (UTC). This caused
Addie to incorrectly reject meeting times as "already passed" when users
specified times in their local timezone.

The fix compares times within the specified timezone context by:
1. Getting current time formatted in the target timezone
2. Comparing ISO strings directly (lexicographically sortable)

This ensures "9:15 AM ET" is compared against "current time in ET", not UTC.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: Add changeset for timezone fix

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Clarify start_time format - no Z suffix

Claude was interpreting "11 AM ET" as "11 AM UTC" and adding Z suffix,
causing meetings to be rejected. Updated schema description to explicitly
tell Claude to NOT add Z or timezone offsets - the timezone parameter
handles that.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: Remove CONCURRENTLY from migration 170

CREATE INDEX CONCURRENTLY cannot run inside a transaction block.
Migrations run in transactions, so we need to use regular CREATE INDEX.
The slack_user_mappings table is small enough that the brief lock is fine.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
The working_group_memberships.user_email field is often NULL because
it's not always populated when members are added. Updated the query
to join with the users table to get the actual email.

This fixes calendar invites not being sent because attendeeCount was 0.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
When creating Zoom meetings, toISOString() was adding a Z suffix which
made Zoom interpret times as UTC instead of the specified timezone.

Example: "11 AM ET" was scheduled for 11:00 UTC = 6:00 AM ET

Fix: Strip the Z suffix so Zoom interprets the time using the timezone
parameter (America/New_York).

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Accept both UUID and Zoom meeting IDs in meeting tools

- Show meeting ID in list_upcoming_meetings output so Claude can see it
- Update get_meeting_details to try UUID first, then Zoom meeting ID
- Update rsvp_to_meeting to try UUID first, then Zoom meeting ID
- Update cancel_meeting to try UUID first, then Zoom meeting ID
- Update add_meeting_attendee to try UUID first, then Zoom meeting ID

This fixes the issue where Claude would try to use Zoom meeting IDs from
meeting links but the tools only accepted our internal UUIDs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* fix: Strip Z suffix from Google Calendar dateTime to fix timezone

Applied the same timezone fix to Google Calendar events that was applied to
Zoom meetings in PR #779. The Z suffix was causing Google Calendar to
interpret times as UTC, resulting in meetings showing 5 hours earlier than
intended for ET.

Renamed formatDateForZoom to formatDateWithoutZ since it's now used for both
Zoom and Google Calendar.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
#781)

- Rename "Research & Ideas" to "Perspectives" across the site
- Fix perspectives article detail page routing (was redirecting to section)
- Add "The Latest" section to homepage showing recent perspectives
- Add 301 redirect from /latest/research to /latest/perspectives
- Update Addie MCP tools with new section URLs

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Change per-item logs to debug level (planner decisions, outreach sends,
  goal reconciliations)
- Make job summary logs conditional (only when there's activity)
- Remove duplicate wrapper logs from scheduler.ts and http.ts
- Convert console.log to logger.debug for MCP/A2A discovery
- Make "Running job" and "Found candidates" logs debug level

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Parse meeting times in specified timezone correctly

Fixed timezone handling end-to-end:
- Added parseDateInTimezone() to interpret input times in the target timezone
- When Claude sends "2026-01-15T13:00:00" for "1 PM ET", we now create a Date
  representing 18:00 UTC (the correct moment for 1 PM ET)
- Both display in Slack and API calls to Zoom/Calendar now show correct time
- Removed formatDateWithoutZ() workaround since Date objects are now correct

Before: "1 PM ET" → Date(13:00 UTC) → displayed as "8 AM ET", but Calendar showed 1 PM
After: "1 PM ET" → Date(18:00 UTC) → displayed as "1 PM ET", Calendar shows 1 PM

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: Add my_working_groups_only filter to list_upcoming_meetings

Added a new parameter to the list_upcoming_meetings tool that filters
meetings to only show those from working groups the user is a member of.

This allows Addie to answer "what meetings are coming up for committees
I'm in?" with a single tool call.

Changes:
- Added working_group_ids option to ListMeetingsOptions type
- Updated listMeetings() to support filtering by multiple group IDs
- Added my_working_groups_only parameter to list_upcoming_meetings tool

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: Rename my_working_groups_only to my_committees_only

Use user-facing terminology - "committees" instead of "working groups".

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Added invite_mode parameter to control who gets invited to meetings:
- all_members (default): Invite everyone in the working group
- topic_subscribers: Only invite members subscribed to the meeting's topics
- none: Create meeting without invites (opt-in mode)

This allows scheduling meetings where people can self-join rather than
being automatically invited.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Addie's probe_adcp_agent was reporting MCP agents as "unreachable" because
validateAgentCards only checked for A2A-style agent-card.json endpoints.
MCP agents use streamable HTTP instead.

Changes:
- Refactored validateSingleAgentCard to try A2A first, then MCP as fallback
- Added 5s timeout to MCP validation using Promise.race
- Returns combined errors when both protocols fail
- Added tests for MCP protocol support

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Add update_meeting tool to Addie for rescheduling/editing meetings
- Fix meetings not displaying on committee detail pages
- Add edit functionality to admin meetings page
- Fix timezone handling when editing meetings in admin UI

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Fix channel activity query to use slack_ts instead of created_at
- Remove aao-admin from exclusion list (was blocking indexing)
- Add access control for private channels based on working group membership
- Filter search results to only show channels user has access to
- Only index private channels that have linked working groups
- Add getAccessiblePrivateChannelIds for efficient membership lookup
- Add getWorkingGroupIdsByUser for local membership queries

This ensures users can only see search results from:
1. Public channels (accessible to all workspace members)
2. Private channels where they are a working group member

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Reduce log noise from scheduled jobs by changing routine success logs
from info to debug level while keeping error logs at info level.

Affected jobs:
- Industry monitor: RSS feed fetching
- Content curator: RSS perspectives, community articles, pending resources
- Outreach scheduler: Proactive outreach

Errors are still logged at info level with a modified message suffix
"with errors" to maintain visibility into failures.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Remove "Founding Members" vs "Members" distinction
- Show single "Members" section with organization logos only
- Filter out individual members (non-organizations) from display
- Remove unused CSS classes (.launch-members, .launch-member, .member-name-link)
- Update dynamic loading to only show members with logos

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: Parse API response correctly in admin meetings page

The admin meetings page was treating API responses as raw arrays instead of
extracting data from the response object structure. The APIs return
{ meetings: [...] }, { series: [...] }, and { meeting, attendees } but
the frontend was assigning the entire response object directly.

- Fix loadMeetings() to extract data.meetings from response
- Fix loadSeries() to extract data.series and handle missing group filter
- Fix viewMeeting() to properly merge meeting and attendees from response

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* feat: Add Schedule button to admin working groups page

Allows admins to schedule a meeting directly from the committee list
without having to navigate to the meetings page first.

- Added Schedule button on each committee row
- Auto-opens scheduling modal via URL parameter (?action=schedule)
- Working group is pre-selected in the modal

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* chore: Clear action param from URL after opening schedule modal

Prevents the modal from re-opening if the user refreshes the page
or bookmarks it while the modal is open.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add proactive reminders for members about incomplete setup tasks:
- Dashboard alerts for missing logo, tagline, and pending join requests
- Addie scheduled job to DM members about missing setup items
- Addie home alerts for same items via Slack home tab

Only targets paying members with active subscriptions.
Rate limited to once per 7 days per nudge type per user.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
@bokelley bokelley force-pushed the bokelley/creative-id-conflict branch from 6c4d758 to 0b32adf Compare January 16, 2026 13:59
@bokelley
Copy link
Copy Markdown
Contributor Author

Closing in favor of PR #794 which targets the 2.6.x release branch

@bokelley bokelley closed this Jan 16, 2026
bokelley added a commit that referenced this pull request Apr 22, 2026
…t#789

The upstream fix landed (PR #789, closing #780) — issue #797 was a duplicate
and is now closed. Update the storyboard YAML, schema doc, and changeset to
reference the merged PR so the removal trigger is "@adcp/client release that
ships #789" instead of an open issue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Apr 22, 2026
closes #2848) (#2885)

* fix(storyboards): inject format_ids[0] via context_inputs in list_formats_integrity (closes #2848)

The @adcp/client (≤5.11) list_creative_formats request builder returns {}
and the runner only forwards envelope fields from sample_request. The
storyboard's `format_ids: ["$context.product_format_id"]` therefore never
reached the wire and the seller answered with its full unfiltered catalog,
making the round-trip assertion fail by coincidence rather than because
the seller substituted formats. Use the runner's context_inputs (applied
after the builder) to inject the captured {agent_url, id} object at
format_ids[0]; document context_inputs in the storyboard schema as a
temporary bridge tied to adcontextprotocol/adcp-client#797.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(storyboards): point context_inputs comments at merged adcp-client#789

The upstream fix landed (PR #789, closing #780) — issue #797 was a duplicate
and is now closed. Update the storyboard YAML, schema doc, and changeset to
reference the merged PR so the removal trigger is "@adcp/client release that
ships #789" instead of an open issue.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(storyboards): tighten context_inputs framing per expert review

Address docs-expert feedback on #2885:
- Lead the context_inputs field doc with the prohibition ("do NOT use
  unless …") instead of the preference, and name the observable symptom
  (unfiltered agent response) an author can diagnose from.
- Add an inline YAML snippet in the schema doc so authors don't have to
  navigate to the media-buy worked example to see the shape.
- Call out that context_inputs silently no-ops on a missing key (distinct
  from $context.<name>'s loud unresolved_substitution), so the default
  path has better failure modes.
- Acknowledge dependency-aware multi-instance dispatch as a legitimate
  non-workaround use so the framing isn't "escape hatch only."
- State type-preservation behavior explicitly.
- Cross-reference from the sample_request field definition and the
  substitution-syntax section so authors land on context_inputs instead
  of scrolling past the field definitions.
- Pin the inline comment to the currently-published @adcp/client 5.10.0
  (not 5.11, which is unreleased) so the version claim doesn't drift
  when 5.11 ships.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
bokelley added a commit that referenced this pull request Apr 22, 2026
…arity gap) (#2891)

* chore(deps): bump @adcp/client to 5.12.0; adjust storyboard baselines

Picks up the SDK's spec-shaped request-builders for log_event,
create_media_buy, list_creative_formats, si_*, sync_governance
(adcp-client#794, #789, #802) and the VALIDATION_ERROR retry-storm
guard (adcp-client#758). Closes most of the framework-mode zod-parity
gap.

Both legacy and framework regress on the bump because adcp-client#794
makes the runner emit every authored package on create_media_buy,
exposing per-package products our catalog does not seed. Adjusts CI
baselines to the new floor; fixture-seeding follow-up tracked
separately.

Framework-only delta vs. legacy is now 5 storyboards / 7 step
failures, listed in the changeset.

* fix: restore registry resolution for @adcp/client in lockfile

The initial bump used a local tarball during validation; the committed
lockfile carried that file:// path, breaking CI which can't resolve it.
Reinstall from the registry so the lockfile points at npm.

* chore(tests): drop run-one-storyboard.ts in favor of the adcp CLI (#2895)

Every use case run-one-storyboard.ts supported is now covered by the
published adcp CLI (shipped in @adcp/client 5.12):

- Single-storyboard diagnostic run: adcp storyboard run <url> <id>
- Single-step debug: adcp storyboard step <url> <id> <step>
- JSON + JUnit output native

run-storyboards.ts stays — the dual-mode CI matrix and per-storyboard
test_kit / /mcp-strict routing it encodes doesn't fit the helper's
single-agent-one-config shape. Retirement tracked as an upstream RFC
for per-storyboard config on runAgainstLocalAgent.

* ci(storyboards): lower baselines to match 5.12 bump without local overlay

My original baselines (42/37) were taken from a local run where I'd
overlaid static/compliance/source/ onto the SDK cache. Without that
overlay, CI sees 38/32 clean on the bump — matching the fixture-seeding
regression documented in the PR. Lower the floor here; the follow-up
fixtures PR (adcp#2894) lifts it back up.
bokelley added a commit that referenced this pull request Apr 22, 2026
…media_buy (#2894)

* chore(deps): bump @adcp/client to 5.12.0; adjust storyboard baselines

Picks up the SDK's spec-shaped request-builders for log_event,
create_media_buy, list_creative_formats, si_*, sync_governance
(adcp-client#794, #789, #802) and the VALIDATION_ERROR retry-storm
guard (adcp-client#758). Closes most of the framework-mode zod-parity
gap.

Both legacy and framework regress on the bump because adcp-client#794
makes the runner emit every authored package on create_media_buy,
exposing per-package products our catalog does not seed. Adjusts CI
baselines to the new floor; fixture-seeding follow-up tracked
separately.

Framework-only delta vs. legacy is now 5 storyboards / 7 step
failures, listed in the changeset.

* fix(storyboards): seed per-package products for multi-package create_media_buy

After adcp-client#794 makes the runner emit every authored package
instead of dropping packages[1+], sellers without matching products in
their default catalog hit `PRODUCT_NOT_FOUND: Package 1: Product not
found: <id>` and cascading step failures.

Wire adcp-client#790's fixture-seeding feature on the six storyboards
whose create_media_buy steps author multi-package payloads. Each now
declares `controller_seeding: true` + a fixtures block so the runner
pre-seeds the per-package products and pricing options via
comply_test_controller before phase 1 — and packages[1+].product_id /
pricing_option_id resolve regardless of the seller's default catalog.

Affected storyboards:
- protocols/media-buy/index.yaml
- protocols/media-buy/scenarios/delivery_reporting.yaml
- protocols/media-buy/scenarios/governance_approved.yaml
- specialisms/creative-generative/generative-seller.yaml
- specialisms/sales-broadcast-tv/index.yaml
- specialisms/sales-guaranteed/index.yaml

* fix: restore registry resolution for @adcp/client in lockfile

The initial bump used a local tarball during validation; the committed
lockfile carried that file:// path, breaking CI which can't resolve it.
Reinstall from the registry so the lockfile points at npm.

* chore(tests): drop run-one-storyboard.ts in favor of the adcp CLI (#2895)

Every use case run-one-storyboard.ts supported is now covered by the
published adcp CLI (shipped in @adcp/client 5.12):

- Single-storyboard diagnostic run: adcp storyboard run <url> <id>
- Single-step debug: adcp storyboard step <url> <id> <step>
- JSON + JUnit output native

run-storyboards.ts stays — the dual-mode CI matrix and per-storyboard
test_kit / /mcp-strict routing it encodes doesn't fit the helper's
single-agent-one-config shape. Retirement tracked as an upstream RFC
for per-storyboard config on runAgainstLocalAgent.

* ci(storyboards): overlay in-repo compliance source onto SDK cache

Storyboards load from @adcp/client's bundled compliance cache (a
snapshot synced from this repo on SDK publish). Spec changes in this
repo are invisible to the runner until the SDK republishes. Overlay
the source tree onto the cache before running so CI validates in-repo
spec changes immediately.

Fixes CI on fixture-seeding PRs whose baselines assumed the overlay
(which previously only existed in local dev).

* ci(storyboards): lower baselines to match 5.12 bump without local overlay

My original baselines (42/37) were taken from a local run where I'd
overlaid static/compliance/source/ onto the SDK cache. Without that
overlay, CI sees 38/32 clean on the bump — matching the fixture-seeding
regression documented in the PR. Lower the floor here; the follow-up
fixtures PR (adcp#2894) lifts it back up.

* ci(storyboards): raise baselines reflecting fixture-seeding lift

* fix(storyboards): align outdoor_video_q2 seed with canonical fixture

protocols/governance/index.yaml pre-existed this PR and seeds
outdoor_video_q2 as a guaranteed/video_15s/\$12 product. Three new
fixtures in this PR (delivery_reporting, governance_approved,
creative-generative) diverged (non_guaranteed/video_30s/\$15), so the
SDK's seed store refused the replay with
  seed_product.outdoor_video_q2: INVALID_PARAMS ... diverges from the
  previously seeded fixture
on every storyboard reached after governance/index.yaml had run.

Match the canonical seed shape (guaranteed / video_15s / fixed_price
12.0) across the three PR-added fixtures. The storyboards' create_media_buy
packages only reference pricing_option_id, so delivery_type + format_id
don't affect the flow — this is purely a seed-body alignment.
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.

3 participants