Skip to content

migrator(v4): P0-5 — v3.x → v4 GA non-destructive payload migrator (Python + TypeScript)#45

Merged
Davincc77 merged 1 commit into
mainfrom
migrator/v3-to-v4-ga-p0-5
May 24, 2026
Merged

migrator(v4): P0-5 — v3.x → v4 GA non-destructive payload migrator (Python + TypeScript)#45
Davincc77 merged 1 commit into
mainfrom
migrator/v3-to-v4-ga-p0-5

Conversation

@Davincc77
Copy link
Copy Markdown
Owner

Summary

  • Adds the R4-P0-5 normative migrator for .klickd v3.x → v4 GA, in both reference SDKs and as a docs-normative spec. Non-destructive, pure, idempotent — operates on the decrypted payload only, never touches the encrypted wire envelope.
  • Wire envelope contract preserved: klickd_version stays "3.0" on disk; only the inner payload advertises payload_schema_version: "4.0" (matches the preview-track invariant already documented in CONTRIBUTING.md).
  • No release, no tag, no SDK version bump, no Zenodo / npm / PyPI publication. Strictly P0-5 docs + migrator code + tests, plus a normative migration spec.

What ships

Surface Path
Normative spec docs/spec/MIGRATION_V3_TO_V4.md
Python migrator packages/pypi/klickd/src/klickd/migrate.py (re-exported via klickd.__init__)
TypeScript migrator packages/@klickd/core/src/migrate.ts (re-exported via @klickd/core index)
Python tests packages/pypi/klickd/tests/test_migrate_v3_to_v4.py (36 cases)
TypeScript tests packages/@klickd/core/src/__tests__/migrate-v3-to-v4.test.ts (30 cases)

Migrator contract (summary — see spec for full rules)

  • needs_migration(payload) / needsMigration(payload) — boolean detector.
  • migrate_payload(payload, *, source_version=None, migrated_at=None, profile_kind="learner", migration_report_ref=None, backup_ref=None) — returns a new dict (Python) / object (TypeScript).
  • migrate_payload_iter_warnings(payload) / migratePayloadIterWarnings(payload) — non-throwing warning surface for manual-review conditions (overlong decisions_locked, non-reserved profile_kind, human_veto_policyethics.locked_actions overlap, missing source-version metadata).

Transform rules (R1–R10) covered by the spec § 3.3:

  1. Stamp payload_schema_version = "4.0".
  2. Default profile_kind = "learner" when absent.
  3. Preserve domain_schema_version verbatim.
  4. Insert RFC-004 v1 migration block (source_version, migrated_at, optional pointer refs).
  5. Preserve identity verbatim.
  6. Preserve every other v3 block verbatim (SPEC.md §33.7).
  7. Never synthesize new safety surface (verification_gates, human_veto_policy, claim_sources, media_profile, …).
  8. Idempotent on v4 inputs.
  9. Locked safety fields (ethics.locked_actions, context.decisions_locked) never mutated.
  10. Unknown top-level keys preserved verbatim.

What is intentionally NOT in scope

  • No registry / vocabulary remap.
  • No re-encryption, salt rotation, or KDF parameter bump.
  • No strict-only enforcement (callers run validate(..., strict=True) separately).
  • No P0-6 strict cross-impl vectors — next focused PR (vectors/v4-ga-strict-p0-6).

Testing

Local results on this branch:

  • python verify_vectors.py59/59 pass (v2.5 + v3.0 + adversarial + v4.0-preview), 0 fail, 0 skip
  • node verify_vectors.mjs42/42 pass (with hash-wasm), 0 fail, 0 skip
  • python scripts/validate_v4_schemas.py → strict v4 schema validations all pass (positive + negative)
  • python -m pytest packages/pypi/klickd/tests/ -q98 passed, 1 skipped (skip is the pre-existing R4-P0-2 wizard-deferred case)
  • cd packages/@klickd/core && npm test96 passed (4 suites, includes the 30 new migrator cases)
  • cd packages/@klickd/core && npm run build → clean ESM + CJS + DTS

Test plan

  • Migrator detection covers all four cases (v3 missing version / v3 explicit / v4 / non-object).
  • Migrator preserves every v3 top-level key for the six v3 example files at the repo root.
  • Migrated v3 examples validate the strict v4 payload schema (with one documented exemption for full_v34.klickd whose v3-era learning_goal.stakes="critical" is tightened by the v4 GA enum — surfaced via warnings, not rewritten, per spec § 3.4).
  • Migrator does NOT mutate input, NOT touch envelope-AAD fields (klickd_version, kdf, cipher, created_at, domain, encrypted), NOT introduce any secret-looking keys.
  • Migrator is idempotent on v3 → v4 → v4.
  • Warning surface flags: missing source-version metadata, overlong decisions_locked, ethics ↔ veto overlap, non-reserved profile_kind.

Follow-up

  • P0-6: strict cross-impl vectors for the v4 GA payload surface on branch vectors/v4-ga-strict-p0-6. Not included here.

…ython + TypeScript)

Adds the R4-P0-5 normative migrator surface in both reference SDKs:

- `docs/spec/MIGRATION_V3_TO_V4.md` (NORMATIVE) — wire-envelope contract
  unchanged (`klickd_version="3.0"`, payload moves to v4 GA fields),
  10-rule transform table, idempotency, manual-review conditions, error
  handling.
- Python: `klickd.migrate_payload`, `klickd.migrate_payload_iter_warnings`,
  `klickd.needs_migration` (pure / non-destructive / idempotent). Stamps
  `payload_schema_version="4.0"`, defaults `profile_kind="learner"`,
  records RFC-004 v1 `migration` block. Preserves every v3 field
  verbatim (SPEC.md §33.7). Never invents safety surface.
- TypeScript: `migratePayload`, `migratePayloadIterWarnings`,
  `needsMigration` — cross-impl parity with Python (same rules, same
  warnings).
- Cross-impl tests: 36 new pytest cases + 30 new jest cases covering
  detection, stamping, pointer refs, non-mutation, default/explicit
  profile_kind, verbatim block preservation, no-synthesis invariant,
  envelope-key untouched, idempotency on v3 and v4 inputs, unknown
  version refusal, warning surface, secret-key non-synthesis, plus
  strict v4 schema validation across all six v3 example files.

No release, no tag, no package version bump. Wire envelope contract
preserved: encrypted v3 files round-trip bit-for-bit under the same
passphrase after payload-only migration.
@Davincc77 Davincc77 merged commit 76a2ff4 into main May 24, 2026
3 checks passed
@Davincc77 Davincc77 deleted the migrator/v3-to-v4-ga-p0-5 branch May 24, 2026 22:59
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