Skip to content

fix(reporting): preserve canonical consumer status contracts - #2911

Merged
bokelley merged 7 commits into
mainfrom
conductor/fix-reporting-content-mismatch-sdk-contract
Sep 14, 2026
Merged

bokelley merged 7 commits into
mainfrom
conductor/fix-reporting-content-mismatch-sdk-contract

Conversation

@bokelley

@bokelley bokelley commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Merge and reviewed-head CI snapshot

Merged at 2026-09-14 17:23:15 UTC as 8ba12c2ace85a88533ce1d56efd35badea51a97c, following the authorized guarded-merge handoff. Live state was rechecked at 2026-09-14 17:34:43 UTC.

  • Reviewed head: a6834d67870253674178d099447af36dd6640b11; base: 39b07141d3bdf6ba650f3625db471ab017b89a33.
  • Current main / merge commit: 8ba12c2ace85a88533ce1d56efd35badea51a97c. Its tree 1771a8ef743b4ddcd89c836cee39563096dac82e is byte-identical to the frozen reviewed head; git diff a6834d67 8ba12c2a is empty.
  • Exact-head check rollup captured before this post-merge body update: 42 SUCCESS, one historical SKIPPED, zero pending or failed checks. The final source Test & Build aggregate passed; independent pinned fc488 qualification and blob/provenance audits remain recorded below.
  • Inline review comments: 0. Eligible non-author human maintainer bmilekic was requested before merge. The recorded approving reviewer is aao-secretariat.

Later post-merge metadata failure: editing this already-merged PR triggered commitlint job 104081910896. It checked out merged main 8ba12c2a; PR-title checks passed, then commit-range linting failed with Invalid revision range 39b07141..a6834d67. The historical PR range is unavailable in that post-merge checkout. This failed workflow remains recorded; it is not a source-test or qualification failure. Further metadata edits may trigger the same workflow behavior. No workflow was manually rerun or cancelled, and no source or guard was changed. The current rollup must not be described as entirely green after that failure.

The following reproduction, validation, and pre-merge handoff records are retained for provenance. The separate geo/starter adoption work and AdCP #7508 regeneration/release gates remain open; this SDK merge does not close them.


Regenerating the SDK from the current AdCP reporting schema produces consumer_status: content_mismatch, but the handwritten ledger union rejects it with TS2322. The existing Zod postprocessor also rejected mismatch_code and omitted its conditional requirements. This derives ledger wire fields and status rules from the canonical schema, checks the consumed revision binding, and preserves mismatch reasons through JSONB storage, retry, and readback. Unsupported conditional schema shapes fail generation explicitly.

Conditional required/forbidden fields are enforced at runtime by Zod. The generated TypeScript interface and ledger type share the accepted fields/status union; compile-only assertions check their agreement. They do not model the conditional combinations as a discriminated union.

The protocol pin remains rc.2. The existing patch changeset applies to the current 14.0.0-rc line; package versions are unchanged by this PR.

Frozen revision and reviewed patch identity

  • Base: 39b07141d3bdf6ba650f3625db471ab017b89a33 (feat(account): complete guarded change feed adoption #2910/feat(negotiation): complete schema-derived proposal verification #2909).
  • Head: a6834d67870253674178d099447af36dd6640b11; tree: 1771a8ef743b4ddcd89c836cee39563096dac82e.
  • Final git diff origin/main...HEAD SHA-256: 3b7ddfa875cf359d3dcfe5aedacd05959822d59cc71e94c614615e74f96935fe.
  • Previous reviewed head: f8bee9e69c60adecb796388e12cc1112d18156cf, base 90ad47b67401d35e0a9ffc99fd0e76252e026a9a.
  • Zero path overlap with intervening main changes. All six original commits are = in git range-diff; the rebased patch SHA-256 remains bbac1949b154de900e4509d3e7d9ae962b3c80b18be1fef74c324c9fa1af4e9f.
  • All 16 reviewed production/generated/test/evidence file blobs are unchanged. Only three new current-candidate evidence files were added after rebase. The pure-rebase tree 524b7a2f7ff309b6256c3571104e82cf0ac5a78d matches the independently simulated clean merge tree.

Key old/new blob identities (identical at both heads):

File Git blob
src/lib/reporting/ledger/types.ts c41fe8cbabbb95eac57d39e99efbee40c1cbcfb5
src/lib/reporting/ledger/status-ingest.ts 5cff4311279884cf0c4a11fb7d20692d11338df2
scripts/generate-zod-from-ts.ts 4b50941e7bb8f04fb34e4509c31d85cf06213266
src/lib/types/schemas.generated.ts 52fb120d8d44d324013d73a5b79d0f1731117ed1

The complete blob manifest and range-diff are retained under .context/rebase-39b07141/. Range-diff SHA-256: dd04174923053df4e420f1afe6d75d441b162590367215033e45c9bb54e5e94d.

Change size and production scope

19 files, +878/-82. The handwritten executable change is confined to two ledger files and the Zod generation pass; most added lines are tests, canonical fixture, and evidence.

Area Files Added / removed
Handwritten ledger runtime/types 2 +14 / -26
Zod generator 1 +73 / -28
Generated rc.2 artifact 1 +12 / -26
Tests and compile-only assertions 5 +351 / -2
Canonical fixture and provenance 2 +191 / -0
Reproduction evidence 6 +229 / -0
Changeset and fixture-format exclusion 2 +8 / -0

Cross-repository reproduction

Both exact AdCP candidates independently failed against SDK checkout 90ad47b67401d35e0a9ffc99fd0e76252e026a9a with status-ingest.ts(288,13) TS2322: generated content_mismatch is not assignable to ReportingLedgerConsumerStatusInputV1.

AdCP #7508 candidate Generate TypeScript SDK failure Original bundle SHA-256
c59427cde5025f273126cc639885f5ce85984df0 job 104010429918, artifact 10352186775 3bd8ddba0dafc6ecb92864f6bd97d28c7d69ff9d6a700a1596838297cee9be32
fc488660c1501d3cb9db71ee3ecfad8316ee924a job 104038964777, artifact 10356276302; failed at 2026-09-14 15:57:43 UTC 82c1932c2d1cc068c6ae99f4ac6710039210332d16ca1e1859cc2849fa029cfc

The full authenticated logs, tarballs, and provenance were downloaded and verified. Current candidate schema/workflow bytes match the preceding versions. The reporting mismatch came from source/rc.3 (#7465), rather than being introduced by either #7508 release candidate.

Original committed evidence and contract audit; additional current-candidate evidence, error excerpt, and hashes.

Exact qualification path

Validate schema PR bundle / Generate TypeScript SDK. The immutable current-candidate workflow step follows npm ci in disposable sdk/. Use verified artifact in sibling bundle/, set PR_HEAD_SHA=fc488660c1501d3cb9db71ee3ecfad8316ee924a, and supply writable RUNNER_TEMP / GITHUB_STEP_SUMMARY. The local replay matches the job's Node 24.20.0 / npm 11.19.0. No AdCP workflow was rerun or cancelled.

Verbatim Generate and build from the PR bundle step
set -euo pipefail
(cd bundle && shasum -a 256 -c latest.tgz.sha256)
node -e "const fs=require('node:fs'); const p=require('./bundle/latest.tgz.provenance.json'); const digest=fs.readFileSync('./bundle/latest.tgz.sha256','utf8').trim().split(/\s+/)[0]; if (p.source_repository !== 'adcontextprotocol/adcp') throw new Error('Unexpected protocol provenance repository'); if (p.source_commit !== process.env.PR_HEAD_SHA) throw new Error('Protocol provenance does not match PR head'); if (p.bundle_sha256 !== digest) throw new Error('Protocol provenance digest does not match checksum')"
bundle_version="$(node -p "require('./bundle/latest.tgz.provenance.json').published_version")"
mkdir -p "${RUNNER_TEMP}/protocol-host/protocol"
cp bundle/latest.tgz "${RUNNER_TEMP}/protocol-host/protocol/${bundle_version}.tgz"
cp bundle/latest.tgz.sha256 "${RUNNER_TEMP}/protocol-host/protocol/${bundle_version}.tgz.sha256"
printf '%s\n' "${bundle_version}" > sdk/ADCP_VERSION
# This is a disposable candidate checkout: align the SDK's AdCP
# metadata without bumping its own package release number.
npm --prefix sdk run sync-version -- --force

python3 -m http.server 8765 --directory "${RUNNER_TEMP}/protocol-host" > "${RUNNER_TEMP}/protocol-http.log" 2>&1 &
server_pid=$!
trap 'kill "${server_pid}" 2>/dev/null || true' EXIT
curl --fail --silent --show-error --retry 10 --retry-connrefused --retry-delay 1 \
  "http://127.0.0.1:8765/protocol/${bundle_version}.tgz" >/dev/null

export ADCP_BASE_URL=http://127.0.0.1:8765
export ADCP_GITHUB_FALLBACK=0
npm --prefix sdk run sync-schemas
npm --prefix sdk run generate-types
npm --prefix sdk run validate-schemas

# build:lib also ensures historical compatibility caches. The primary
# cache above remains the PR bundle; older pinned bundles come from
# the normal public host.
unset ADCP_BASE_URL ADCP_GITHUB_FALLBACK
npm --prefix sdk run build:lib

bundle_digest="$(node -p "require('./bundle/latest.tgz.provenance.json').bundle_sha256")"
{
  echo '### TypeScript SDK validation'
  echo
  echo "- SDK commit: \`$(git -C sdk rev-parse HEAD)\`"
  echo "- Protocol commit: \`${PR_HEAD_SHA}\`"
  echo "- Bundle SHA-256: \`${bundle_digest}\`"
} >> "${GITHUB_STEP_SUMMARY}"

Validation and review gates

  • Identical four-file reporting selection: 47/47 on the current rc.2 pin and 47/47 after rc.4 bundle generation, with PostgreSQL 16 and zero skips. The files are test/generate-zod-consumer-status-content-mismatch.test.js, test/generate-zod-consumer-status.test.js, test/lib/reporting-status-ingest-validation.test.js, and test/lib/reporting-status-ingest-pg.test.js. Canonical field combinations, all mismatch codes, storage/replay/readback, and generated/ledger agreement are covered. These identical selections also passed on the final rebased head: current-pin rc.2 and generated fc488 rc.4 both 47/47, zero failures or skips.
  • Previous frozen f8bee9e69 exact-head CI was fully green after one evidence-backed adapter-job rerun (54/54). The original local workflow replay failed on unchanged base with exact TS2322 and passed with the reporting fix. Independent root audit confirmed generation and PostgreSQL validation with no code/security blocker.
  • Rebased head a6834d67: all applicable checks in fresh CI run 34868616695 and the exact-head check rollup have passed. The final Test & Build aggregate passed at 2026-09-14 17:05:04 UTC; commitlint passed. The automated AI review was skipped while Draft; the readiness transition may trigger its normal review workflow. The independent exact-head delta audit approves with no blockers, and the second-model delta stack reports no new blockers. The complete exact fc488 local qualification passed with exit 0 under Node 24.20.0/npm 11.19.0, followed by explicit typecheck and 47/47 PostgreSQL-backed tests. Exact-head CI, qualification, and independent audit gates are satisfied for human review. Prior-head green results do not qualify this new head.
  • Exact fc488 qualification log SHA-256: 496fe58bf8b413cf4feac147bf5173c6a20b560d0d265f05c836b29d61096310; post-qualification typecheck/test log SHA-256: c99fb6f79386019067364ece3c4127bd3388afade12553a4d3bc10151293c96c. The workflow summary records SDK a6834d67, protocol fc488660, and verified bundle digest 82c1932c…. All commands completed with exit 0.
  • Required pre-push formatting, TypeScript typecheck, library build, and Conventional Commits validation passed on the new head. The rebased current-pin four-file suite independently passed 47/47 with PostgreSQL 16 and no skips. Rebase preserves the already-validated runtime/generated patch.
  • Fresh exact-head CI leaf logs: fast lanes 17,902 tests: 17,890 passed, 12 skipped, zero failures; slow lane 450/450; adapter integration 54/54, zero skips, without a new-head retry. Package artifact smoke, formatting/generated checks, lint, typecheck, builds, adopter/examples, compatibility matrices, reference sellers, and security checks also passed.
  • Prior proportional full validation is preserved: fast group 17,882 tests with initial environment failures, all failed/cancelled cases matched successful corrected-environment retries; slow group449/449 and workspace48/48. The original failed fast run remains recorded as failed. Current-pin package checks and clean-room Node/Bun/MCP/browser validation passed in the prior audit.

The independent delta reviewer approved exact a6834d67 in the separate review session. Prior review included parallel DX/protocol/code/security experts plus the Codex second-model stack. Its conditional-schema drift and inherited object-property findings were fixed and re-reviewed before rebase. The new delta audit re-derived range/blob identities and checked integration with main; the Codex delta stack reviewed supplied source context because its checkout read tools were unavailable, and did not independently execute tests.

The additional independent root re-audit of exact a6834d67 also confirmed the main/base and merge tree, reviewed blob/range identity, authenticated fc488 evidence, and an independent pinned fc488 sync/generate/validate/build replay. It found no code, security, or correctness blocker.

Rebase/qualification evidence is sealed in rebased-reporting-qualification-evidence.tgz (SHA-256 ed5872cde2a5f17ac8d79489ec5e57e023b5c84de7362cae0ea66253aaa287c3): 55 verified files, including the artifact, provenance, replay logs, and delta review. The archive records its earlier CI-pending snapshot; final CI is recorded separately.

Separate geo-null workstream and adoption limits

The wider rc.4 example package check previously reproduced seller-3.2-starter.ts:102,108 errors on unchanged base: the starter spreads nullable purchase input into accepted terms even though it rejects targeting overlays. Accepted snapshots forbid those null clear commands. The separate geo-null workstream owns supported-field snapshot construction, six targeting-array alias collision fixes in scripts/generate-types.ts (four nullable-input aliases plus two enum-versus-array aliases), and their boundary tests; its fix is not absorbed here. It has the final reporting head for disposable composition. No new targeting or generator edits were made during rebase.

The canonical “currently required revision” prose condition requires a separate store/producer contract; this handler uses point lookup and verifies identity/content binding. Newer mismatch-issue opened_at lifecycle and optional escalation remain adoption work. This PR does not claim full rc.3/rc.4 reporting conformance or closure of AdCP #7404 / the reporting framework.

Pre-merge human handoff

Historical handoff: maintainer bmilekic was requested on frozen a6834d67 before merge. The user authorized normal guarded auto-merge after reassessing the actual dependency graph. Existing main rules require approving review, last-push approval, applicable code-owner review, resolved review threads, required CI, and CodeQL; those gates remain in force. The completed exact-head source CI and independent qualification/audits are recorded above. Metadata and readiness checks remain visible in the current check rollup.

Geo-null is not a prerequisite for this PR. The reporting fix preserves the rc.2 pin and passes the pinned fc488 sync/generate/validate/build replay independently, without the geo patch. The geo owner confirmed no correctness dependency requires landing first and can rebase/qualify after this fix. At the ordering decision, that separate workspace was uncommitted on 39b07141, with no PR or push; its own Draft-only review/adoption gates remain separate.

The actual supply-path dependency is this SDK fix → upstream AdCP #7513 qualification and guarded merge → client #2908 pinning the final merged upstream SHA and satisfying its own gates. The exact upstream Generate TypeScript SDK failure at head 38190a864e3585d970869df7cb194e6e582b111b is the same reporting TS2322 at status-ingest.ts:288. No supply-path or targeting changes are absorbed here.

The committed immutable evidence retains the historical Draft/auto-off authorization at capture time. This current handoff supersedes that process hold; it does not alter the reviewed source, tests, generated blobs, or release gates.

AdCP #7508 must remain Draft until this SDK fix lands on adcp-client main, its release branch is regenerated from current AdCP main, and the exact Generate TypeScript SDK check passes on that release head. Local candidate replay is evidence for this SDK fix, not qualification of a future release head.

Normal auto-merge is authorized only through the existing guarded review/CI process for exact a6834d67; no administrator bypass is used. npm publication, release, tag, edits to AdCP #7508, AdCP workflow reruns/cancellations, and branch-protection changes remain outside this task. The sole old-head SDK adapter-job retry was evidence-backed and passed; new-head CI follows the authorized rebase push.

@bokelley
bokelley force-pushed the conductor/fix-reporting-content-mismatch-sdk-contract branch from f8bee9e to a6834d6 Compare September 14, 2026 16:26
@bokelley
bokelley marked this pull request as ready for review September 14, 2026 17:17
@bokelley
bokelley requested a review from bmilekic September 14, 2026 17:17
@bokelley
bokelley enabled auto-merge (squash) September 14, 2026 17:19

@aao-secretariat aao-secretariat Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Ladon verdict: Approve

Approve — clean diff, no blocking findings.

Checked:

  • Reporting consumer-status Zod constraints are now derived from the pinned canonical schema and fail-closed on unexpected arm shapes.
  • ReportingLedgerConsumerStatementV1 widened to extend the generated wire type — additive, no shipped-shape change on the current rc.2 pin (consistent with witness-not-translator).
  • Revision-binding check correctly moved from consumer_status==='received' to observed_revision_content_sha256!==undefined, covering both received and content_mismatch per the revision_binding invariant.
  • Changeset (patch) does not understate impact — no removed/renamed exports, param flips, or response-shape changes.
  • New paths covered by codegen, validation, and PG roundtrip tests.

No Critical/High/Medium findings. No high-risk paths, no gated paths, no author team gate. Falls through to row 9.

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.

1 participant