* feat(sqlite): migrate persisted media to canonical facts and stop legacy writes
PR 3 of the media legacy retirement program — the operator-approved
canonical cutover.
- openclaw doctor --fix owns one idempotent migration: active
transcript_events rows canonicalize to __openclaw.media (facts-first
gap-fill, bare legacy kinds to fact.kind, transcribed indexes and
workspace dirs onto per-fact fields) via the transcript replacement
owner; cold plain/.zst archives rewrite through temp-file + codec
readback + event/id verification + atomic replace; trajectory
runtime snapshots canonicalize IN PLACE (telemetry preserved, never
row deletion). Invalid JSON, genuinely ambiguous legacy-only sparse
alignment, or a changed source aborts that owner without partial work;
reruns are no-ops.
- Per-agent schema advances to v16 as a pure downgrade guard (main
independently took v15 for board/session-sharing tables; no
columns/tables/indexes change here, shared-state DB untouched). v15
databases repair canonical indexes before the version assertion so
repairable installations never strand.
- The user-turn builder stops writing top-level legacy Media* fields;
shouldPersistStructuredMediaEntries and the aligned projection mode
are deleted; the generic transcript append boundary canonicalizes
every message role so SDK/mirror writers cannot mint new legacy rows.
- Internal persisted-reader legacy fallbacks are removed; the public
SDK projection stays until retirement PR 4's window expires.
Hardening from three adversarial review rounds, each with fixture
regressions: in-place trajectory canonicalization instead of row
deletion; repair-before-assert on the v15 path; all-roles append
canonicalization; duplicate-preserving exact row rewrites; v0-v15
reopen guards; complete canonical facts bypass compact legacy
projections (PR-1 dual-write rows migrate cleanly); SQLite LIKE
underscore escaped so populated foreign databases are never claimed.
* fix(sqlite): align schema-support metadata and gates with the v16 cutover
package.json agent schema support advances to 16; verifier and board
parity fixtures run doctor migration before steady-state access (the
production guards were correct); two test-only exports removed; the
migration module registered in the doctor raw-SQLite allowlist.
* test(telegram): consolidate bot test harness
* test(plugin-sdk): expose isolated test state
Promote the isolated OpenClaw test-state lifecycle through a narrow published Plugin SDK subpath so extension tests no longer import private core helpers. This intentional SDK surface addition is maintainer-approved.
* test(telegram): use public test-state seam
* test(plugin-sdk): keep test state local-only
Match the existing channel test-helper boundary: bundled extension tests can import the focused SDK source entrypoint, while ordinary builds and the published npm package exclude it. The earlier public classification existed only on this unmerged PR branch and was never a shipped contract.
* test(plugins): map test-state in package boundaries
* fix(release): terminate Windows package command trees
* fix(release): type package runner test output
* fix(release): scope package runner normalization to Windows
* test(release): run package timeout proof on Windows CI
---------
Co-authored-by: TheAngryPit <16145902+TheAngryPit@users.noreply.github.com>
Co-authored-by: Peter Steinberger <steipete@gmail.com>
* feat(models): add Claude Opus 5 support
* test(models): align Opus 5 setup fixtures
* test(models): update ambient Opus 5 detection
* fix(models): reconcile Opus 5 support with main
* feat(sdk): always persist media facts and ship facts-first replacements for legacy Media* surfaces
PR 1 of the media legacy retirement program (audit-frozen, 4 PRs).
- Every media-bearing user turn now persists normalized __openclaw.media
facts unconditionally while continuing to emit the legacy top-level
Media* projection byte-identically (dual-write bridge; the conditional
shouldPersistStructuredMediaEntries gate now always includes media).
- New replacement APIs, shipped before any removal: typed hook media
facts (media[], originalMedia[], mediaStagingPending) on message
events; {{AttachmentPath}}/{{AttachmentUrl}}/{{AttachmentContentType}}/
{{AttachmentDir}}/{{AttachmentIndex}} template variables; focused
openclaw/plugin-sdk/media-local-roots subpath split out of the
deprecated agent-media-payload facade.
- Every legacy surface carries @deprecated naming its replacement, under
one named compatibility record media-legacy-projection with the
operator-approved removeAfter 2026-10-01 (two release trains; deletion
additionally gates on a clean published-plugin artifact sweep).
- Generic transcript append invariant documented; SDK migration, hooks,
and configuration docs updated to the facts-first path.
Writer golden matrix proves legacy bytes and model prompt bytes are
unchanged while nested facts become unconditional. 2,189 broad media
tests green; SDK api-baseline regenerated on fresh-env Testbox.
* feat(sdk): register media-local-roots subpath exports and deprecation metadata
Completes PR 1: package export map for openclaw/plugin-sdk/media-local-roots
plus the deprecated-subpath inventory and doc metadata entries for the
media-legacy-projection record.
* chore(sdk): track media-local-roots entrypoint and deprecated-export budgets
* fix(sdk): keep deprecated MSTeams buildMediaPayload re-export through the compat window
Deleting shipped runtime-api re-exports belongs to retirement PR 4 after
the media-legacy-projection window; PR 1 only deprecates. Also formats
the migration-guide schedule table.
* docs: regenerate docs map for media migration additions
Run-identity supersession (#113230) resolves the scenario this heuristic
softened: superseded runs and rerun-attempt leftovers are filtered before
classification, so aggregate-FAILURE-with-green-duplicates now classifies
as GREEN or PENDING on evidence. The only remaining reachable case —
identity-less app check runs posting duplicate same-name results — is
genuinely ambiguous and now honestly exits FAILING (15) instead of the
special verify-manually exit 17.