Skip to content

fix: resynchronize current session metadata on ACP v2 resume - #717

Merged
benbrandt merged 1 commit into
mainfrom
fix/session-metadata-sync
Oct 30, 2026
Merged

benbrandt merged 1 commit into
mainfrom
fix/session-metadata-sync

Conversation

@benbrandt

Copy link
Copy Markdown
Member

Summary

  • Add one v2 session-info metadata owner at the common send boundary. Shared v1-shaped and direct v2 publications use the same shallow patch state. Omission leaves values unchanged, top-level nulls remove keys, and nested objects replace whole values.
  • On every successful resume, after replay/live-event draining and before the response, clear retained client metadata with _meta: null, then restore the agent's currently known metadata when nonempty. Serialize both frames with live session-info updates so an older restoration cannot overwrite a newer patch.
  • Keep metadata for the active session lifetime, including full replay. Resume reinstalls SessionState, so the metadata lifetime must not follow that object's identity. Seed known native thread status before releasing new live events. Close/reopen starts a fresh metadata lifetime.
  • Carry the current failure reference across active reinstallation. Clear published failure metadata when that incident resolves, preserving sibling metadata and checking the ID/revision so a late resolution cannot remove a newer incident.
  • Preserve notification params._meta through the shared v2 conversion path, but do not store or replay it as entity metadata. Keep v1 wire behavior unchanged.

Checked against ACP a965f1f1: docs/protocol/v2/extensibility.mdx:103-150 defines metadata replacement/removal and explicit resynchronization clears. docs/protocol/v2/session-setup.mdx:355-358 recommends current session info after replay and before the response, including omitted/null replayFrom.

Scope

This synchronizes currently known session_info_update metadata. It does not invent a deep merge for extension namespaces, copy raw session-list snapshot metadata into entity patches, or reconstruct every metadata field from persistent storage. Writers sharing a top-level namespace still need to compose complete values; that cleanup is separate, with the new serialized domain-patch API available for it. Newer upstream auth/proxy/background schema additions are not adopted here. No review/checklist Markdown file is included.

Validation

  • npm run typecheck
  • npm run build
  • npm test: 2,358 passed, 39 skipped
  • npm run test:integration: all 19 passed
  • npm run codex-test -- -p "Reply with exactly OK. Do not use tools or modify any files." -o summary: completed with end_turn
  • git diff --check
  • Opt-in E2E tests were not run.

Coverage includes shallow replacement and removals, nested null values, clearing keys the agent has never seen, JSON copies, notification-only metadata, serialization under backpressure, queued patches, disposal during restoration, write-failure recovery, failure revision matching, active resumes with/without replay, close/reopen, current failure continuity, and post-close publication fencing. The real-Codex foreground-state integration covers all replay settings with the extended info synchronization sequence.

@benbrandt
benbrandt merged commit 927c480 into main Oct 30, 2026
6 checks passed
@benbrandt
benbrandt deleted the fix/session-metadata-sync branch October 30, 2026 22:55
benbrandt added a commit that referenced this pull request Nov 1, 2026
## Summary

- Compose complete v2 `codex` and `jetbrains.air` values in their owned
writers, using the serialized session metadata owner from #717. A
status/goal/failure/report/archive update no longer drops sibling fields
merely because v2 replaces the whole top-level namespace value.
- Keep composition after event routing, so child-view facts read and
update the child's metadata rather than the parent's.
- Generalize the existing AIR metadata builder for multiple owned fields
and reuse it for event-handler facts, goal publication, file-change
reports, and archive updates. Raw transport metadata still follows
shallow replacement semantics; this does not introduce a generic deep
merge.
- Retain metadata through nested close/archive operations until the
final publication fence is sealed. Foreground teardown still happens at
runtime close, but archive can compose its final metadata with the
current sibling values before disposal. Late publication remains fenced.
- Preserve accompanying session info fields in the same composed update.
Keep all v1 payloads unchanged.

Checked against ACP `a965f1f1`,
`docs/protocol/v2/extensibility.mdx:103-150`: each top-level metadata
value is replaced whole, and nested nulls are ordinary data. Producers
that share a namespace therefore need to construct its current complete
value, rather than relying on clients to deep-merge their partial
objects.

## Scope and cost

This preserves the current namespace layout and extension contract.
Complete namespace updates may repeat unchanged values, including
file-change reports and failure revisions. Splitting metadata keys or
moving request-scoped report data to a different notification location
would be a separate compatibility decision. Native setup seeding and
newer upstream schema additions are not redesigned here. No
review/checklist Markdown file is added.

## Validation

- `npm run typecheck`
- `npm run build`
- `npm test`: 2,365 passed, 39 skipped
- `npm run test:integration`: all 19 passed
- `npm run codex-test -- -p "Reply with exactly OK. Do not use tools or
modify any files." -o summary`: completed with `end_turn`
- `git diff --check`
- Opt-in E2E tests were not run.

New wire tests exercise the actual goal, local-command file-report,
typed-failure, goal-clear, and archive sequence on both protocol
versions, including post-archive suppression. They also cover
independent Codex fields, concurrent AIR writers, unrelated
JetBrains/root fields, nested nulls, and routed child isolation. A
metadata-owner test covers accompanying title/activity fields. All
existing snapshots, including v1 snapshots, remain unchanged.
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