Schema epoch inventory (1.0)

Status: implemented in 0.9.3 — public schema targets are integer 1 only (no dotted .x forms); data-root marker + remediation UX shipped
Programme: pre_release_roadmap_1_0.md §8
Package baseline: 0.9.3 (epoch implementation)
Approved: 2026-07-24 (owner clean-slate + integer-1 standardisation); cut: 2026-07-24 as v0.9.3

Locked convention

  1. Classify every version-like value before changing it.

  2. Public persisted schema versions are integers only — use 1, never "1.0", "2.0", or other dotted .x forms.

  3. Canonical transcript / speaker-map / state envelopes that today use "1.0" or "2.0" → integer 1 in the epoch.

  4. Public persisted string schema IDs → transcriptx.<domain>.v1 (.v1 suffix is an ID token, not a dotted schema number).

  5. Refuse or isolate pre-epoch artifacts; no long-lived compatibility adapters for wiped pre-public data.

  6. Write schema_epoch / public-schema epoch marker at managed data-root; detect early; explain clearly in GUI and supported remediation surfaces (not a new public analysis CLI).

  7. Never renumber, reuse, or reset public schema IDs after 1.0.

  8. Policy / prompt / algorithm-semantics / cache identity strings are not public schema_version numbers — do not cosmetic-reset them unless the inventory row says so. Prefer leaving them unchanged across the epoch.

Retain / wipe decisions (approved)

Asset

Decision

Compatible managed transcripts (content)

Retain (or reimport); schema stamp → integer 1

Source recordings

Retain — never touch for epoch neatness

Speaker-map sidecars

Owner clean-slate: backed up then removed from live trees for testing; restore from backup when needed. Live schema stamp → integer 1 (today often "1.0")

Speaker profiles / voice

Owner clean-slate: backed up then removed from live data/speaker_profiles for testing

Other incompatible derived state (run outputs, manifests/run_results, caches, indexes, groups, corrections, cleanup journals, local config overrides as needed)

Refuse / remove via supported reset path only

Automatic deletion without user action

Forbidden (owner-driven wipe for testing is explicit and separate)

Backup location (2026-07-24)

Owner-local clean-slate backup (outside the git worktree; path not recorded in-repo):

  • Directory name: epoch_clean_slate_2026-07-24/

  • library_transcripts_speaker_maps/ — from the live library speaker-maps tree (168 files)

  • working_tree_speaker_maps/ — from repo data/transcripts/**/*.speaker_map.json

  • working_tree_speaker_profiles/ — from repo data/speaker_profiles

speaker_id_to_db_id

Treat as legacy / unused for current product (no DB-backed speaker features in 0.9.x). Sidecars may still contain an empty {} object. Do not invent new DB linkage in the epoch; safe to keep the field as an empty object for wire compatibility or drop in a later cleanup once readers tolerate absence.

Inventory rows

Paths abbreviated under src/transcriptx/.

Public persisted → integer 1 / rename string IDs

path

current

class

action

tests / fixtures

notes

core/pipeline/module_outcomes.py RUN_RESULTS_SCHEMA_VERSION

2

public_persisted

→ 1

run outcome / contract tests

Highest impact

web/services/run_cleanup/models.py CLEANUP_RESULT_SCHEMA_VERSION

2

public_persisted

→ 1

cleanup tests

web/layouts/specs.py CURRENT_LAYOUT_SCHEMA_VERSION

2

public_persisted

→ 1

layout store tests

Drop dual-accept after wipe

core/config/persistence.py CONFIG_SCHEMA_VERSION

1

public_persisted

keep 1

config tests

speaker_profiles/versioning.py SCHEMA_VERSION

1

public_persisted

keep 1

speaker profile tests

speaker_profiles/voice/versioning.py VOICE_SCHEMA_VERSION

1

public_persisted

keep 1

voice tests

services/corrections_studio/normalize.py STUDIO_SCHEMA_VERSION

2

public_persisted

→ 1

corrections tests

core/utils/state_schema.py STATE_SCHEMA_VERSION

"2.0"

public_persisted

1 (integer; no dotted form)

state tests

io/import_metadata/schema.py SIDECAR_SCHEMA_VERSION

1

public_persisted

keep

import tests

io/import_admission.py SCAN_HANDLE_SCHEMA_VERSION

1

public_persisted

keep

admission tests

web/action_menus/prefs.py INTERFACE_SCHEMA_VERSION

1

public_persisted

keep

observability/run_performance/schema.py RUN_PERFORMANCE_SCHEMA_VERSION

1

public_persisted

keep

core/pipeline/manifest_builder.py SCHEMA_VERSION

1

public_persisted

keep

core/pipeline/contracts.py SCHEMA_VERSION

1

public_persisted

keep

core/analysis/bertopic/schema.py SCHEMA_VERSION

1

public_persisted

keep

core/analysis/transcript_quality/analyze.py SCHEMA_VERSION

1

public_persisted

keep

core/analysis/interactions/graph_export.py SCHEMA_VERSION

1

public_persisted

keep

core/analysis/group_llm_synthesis/schemas.py COLLECT_SCHEMA_VERSION

1

public_persisted

keep

core/analysis/llm_support/action_items_contract.py LLM_ACTION_ITEMS_GROUP_SCHEMA_VERSION

2

public_persisted

→ 1

group LLM tests

core/analysis/llm_custom_qa/versioning.py COMMIT_MARKER_SCHEMA_VERSION_V1 / _V2

"1" / "2"

public_persisted

Rename to a single COMMIT_MARKER_SCHEMA_VERSION = 1 (integer); delete _V1/_V2 symbol names

custom QA tests

Dual live markers + V2 in the name are confusing once everything is epoch-1; collapse writers/readers to one constant

Speaker-map wire speaker_map_schema_version

"1.0"

public_persisted

1

mapping service / fixtures

Written by SpeakerMappingService

core/analysis/emotion/lexical_pipeline.py SCHEMA_VERSION

transcriptx.emotion_result.v1

public_persisted

transcriptx.emotion_result.v1

emotion fixtures

core/analysis/contextual_emotion/__init__.py SCHEMA_VERSION

contextual_transcriptx.emotion_result.v1

public_persisted

transcriptx.contextual_emotion_result.v1

core/analysis/fine_grained_emotion/__init__.py SCHEMA_VERSION

fine_grained_transcriptx.emotion_result.v1

public_persisted

transcriptx.fine_grained_emotion_result.v1

core/analysis/topic_shift/semantics.py SCHEMA_VERSION

transcriptx.topic_shift_result.v1

public_persisted

transcriptx.topic_shift_result.v1

core/analysis/topic_shift/enrichment.py ENRICHMENT_SCHEMA

transcriptx.topic_shift_enrichment.v1

public_persisted

transcriptx.topic_shift_enrichment.v1

core/analysis/topic_shift/store.py INDEX_SCHEMA

transcriptx.topic_shift_artifact_index.v1

public_persisted

transcriptx.topic_shift_artifact_index.v1

core/analysis/emotion_family/generational_store.py index/manifest

emotion_family_*_v1

public_persisted

transcriptx.emotion_family_*.v1

Canonical transcript → integer 1

path

current

class

action

notes

domain/canonical_transcript.py CANONICAL_SCHEMA_VERSION

"1.0"

canonical_transcript

1

No dotted forms

io/transcript_schema.py SCHEMA_VERSION

"1.0"

canonical_transcript

1

Fixtures/goldens must follow

Contract string IDs

path

current

action

llm_support/action_items_contract.py LLM_ACTION_ITEMS_SCHEMA_ID

transcriptx.llm_action_items.v2

.v1; remove v1 coerce after wipe

llm_custom_qa/versioning.py V2_SCHEMA_ID

transcriptx.llm_custom_qa.v2

.v1 as sole live ID

Already-transcriptx.*.v1 IDs

…v1

keep

llm_feedback/models.py EVENT_SCHEMA_ID

transcriptx.llm_feedback_event.v1

transcriptx.llm_feedback_event.v1

speaker_profiles/versioning.py *_SCHEMA_ID

speaker_profile*.v1

transcriptx.speaker_profile*.v1

speaker_profiles/voice/versioning.py voice schema ids

voice_*.v1

transcriptx.voice_*.v1

Journal / policy / cache / semantics / prompt / package

path

current

class

action

web/services/run_cleanup/models.py JOURNAL_SCHEMA_VERSION

3

journal

1 (integer epoch; no dotted form)

core/utils/rename/journal.py JOURNAL_SCHEMA_VERSION

1

journal

keep

web/services/run_cleanup/models.py CLEANUP_POLICY_VERSION

7

policy

keep (behaviour generation, not schema envelope)

Other policy IDs

various

policy

keep

emotion_family / clip / voice excerpt cache versions

v3 / 2 / 1

cache

keep unless wipe invalidates caches deliberately

algorithm / semantics / prompt versions

various

non-schema

keep method fingerprints; see Public module ids below for _vN in registry names

pyproject.toml / __version__

0.9.2

package

bump via normal release when epoch implementation ships

Public analysis module ids (not schema envelopes)

Registry scan: semantic_similarity is the only public module id / package that embeds a _vN suffix. Older siblings still exist as unversioned legacy ids (not named _v1).

Module id

Package

Status today

Epoch / 1.0 action

semantic_similarity

core/analysis/semantic_similarity/

Default / current product path; SCHEMA_VERSION = "semantic_similarity.1.1" is method identity

Renamesemantic_similarity after legacy retirement (registry, package dir, config analysis.semantic_similarity*, UI presets, profile ids *_v2, artifact basenames, docs). Retarget method string so it does not imply a second live module (e.g. keep a semantics fingerprint without requiring _v2 in the module id).

semantic_similarity

core/analysis/semantic_similarity/

legacy: True

Retire / remove from public registry (no reason to keep a parallel legacy module for 1.0)

semantic_similarity_advanced

same legacy package

legacy: True

Retire / remove

llm_custom_qa

…/llm_custom_qa/ (analyze_v2.py internal)

Public id already unversioned

Keep module id; collapse dual commit-marker / schema-id writer symbols (see row above)

Why not “keep _v2 as method identity” forever: same naming smell as COMMIT_MARKER_SCHEMA_VERSION_V2 — the product default should not look like a temporary upgrade path. Group aggregation already uses unversioned agg id semantic_similarity while preferring semantic_similarity payloads — rename aligns those.

Breakage surface if renamed without retiring legacy: config/presets collision on id semantic_similarity; must delete or archive legacy modules first. Owner clean-slate / pre-public wipe means no long-lived module-id alias map is required.

Near misses (not public module ids): artifact schema strings (transcriptx.emotion_result.v1), profile keys (fast_v2), voice output path voice/v1/ — handled under schema-id / layout rules, not module rename.

Compatibility helpers to archive/remove after reset

Location

Role

pipeline/module_outcomes run_results support gate

Update to epoch-1 only

web/layouts/store.py layout schema dual-accept

Drop pre-epoch after wipe

web/services/run_cleanup/journal.py schema decode dispatch

Epoch-1 journal only after reset

llm_support/action_items_contract.py v1 coerce

Remove after wipe

llm_custom_qa dual V1/V2 readers

Collapse to epoch-1

core/utils/state_schema.migrate_state_entry

Replace with refuse/remediate for pre-epoch

Readers accepting "1.0" / "2.0" dotted schema stamps

Accept integer 1 only after migration

Emotion/corrections legacy payload builders

Remove or quarantine post-wipe

Legacy semantic modules + semantic_similarity id

Retire legacy; rename v2 → unversioned semantic_similarity (see Public module ids)

llm_custom_qa COMMIT_MARKER_SCHEMA_VERSION_V1/_V2

Single COMMIT_MARKER_SCHEMA_VERSION = 1

Transition UX design

Keep within existing public surfaces — no new public analysis CLI.

Proposed behaviour

  1. Data-root marker: write schema_epoch (or equivalent) at managed data root when creating/opening an epoch-1 store.

  2. GUI preflight: on app start / library open, detect missing or pre-epoch marker; block principal work with clear copy naming the incompatible root.

  3. Remediation choices (no auto-delete):

    • Create fresh data directory (recommended default path)

    • Optional inventory/export of compatible transcripts before reset

    • Supported reset of incompatible derived state only (with reset report)

    • Backup guidance link to docs (owner backup path documented above)

  4. Typed Python workflow / internal maintainer utility: same detection + remediation for automation; not advertised as analysis CLI.

  5. Tests: recordings never touched; compatible transcripts retained by default; epoch-1 store opens in later 0.9.x / 1.0 candidates.

Checklist

  • GUI preflight detects incompatible roots before work begins

  • Typed Python workflow and/or internal maintainer utility

  • Optional inventory/export before reset path

  • Explicit “create fresh data directory” path

  • No automatic deletion of user data

  • Precise identification of which root is incompatible

  • Backup guidance in GUI/docs

  • Reset report when supported reset path is used

  • Tests proving unrelated source recordings are never touched

  • Retain decision for managed transcripts recorded (retain / reimport OK)

  • Validation that a 0.9 epoch-1 store opens unchanged later (epoch-1 marker + stamps frozen in 0.9.3; reconfirm on later 0.9.x / 1.0 candidates)

Doc / script locations referencing old versions

location

what it encodes

update in epoch PR?

docs/contracts/output-contract-v1.md

run_results schema_version 2; speaker_map "1.0"

yes → integer 1

docs/run_outcome_contract.md

run truth / schema refs

yes

docs/contracts/speaker_profiles_*.md

schema_ids

yes if renamed

docs/contracts/llm_feedback_v1.md

event schema id

yes if renamed

Fixtures under tests/fixtures/ encoding schema_version 2 / "1.0" / *_v2

wire values

yes — regenerate

Goldens / characterization dumps

yes

This inventory

actions

mark done after epoch

Sign-off

  • Inventory rows drafted for known version-like constants

  • Retain/wipe decisions accepted (incl. owner clean-slate backup of maps/profiles)

  • Transition UX design proposed

  • Integer-only public schemas → 1 (no dotted .x forms) standardised

  • Human sign-off — ready for epoch implementation (2026-07-24)