cjm-transcript-correction-core 0.0.3__tar.gz → 0.0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cjm_transcript_correction_core-0.0.3/cjm_transcript_correction_core.egg-info → cjm_transcript_correction_core-0.0.5}/PKG-INFO +39 -7
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/README.md +35 -3
- cjm_transcript_correction_core-0.0.5/cjm_transcript_correction_core/__init__.py +1 -0
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/cjm_transcript_correction_core/cli.py +157 -8
- cjm_transcript_correction_core-0.0.5/cjm_transcript_correction_core/graph.py +1915 -0
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/cjm_transcript_correction_core/journal.py +31 -12
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/cjm_transcript_correction_core/models.py +75 -3
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/cjm_transcript_correction_core/pipeline.py +16 -7
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/cjm_transcript_correction_core/signals.py +52 -1
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5/cjm_transcript_correction_core.egg-info}/PKG-INFO +39 -7
- cjm_transcript_correction_core-0.0.5/cjm_transcript_correction_core.egg-info/entry_points.txt +5 -0
- cjm_transcript_correction_core-0.0.5/cjm_transcript_correction_core.egg-info/requires.txt +4 -0
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/pyproject.toml +4 -1
- cjm_transcript_correction_core-0.0.5/tests/test_graph.py +701 -0
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/tests/test_journal.py +15 -2
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/tests/test_models.py +33 -1
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/tests/test_signals.py +31 -0
- cjm_transcript_correction_core-0.0.3/cjm_transcript_correction_core/__init__.py +0 -1
- cjm_transcript_correction_core-0.0.3/cjm_transcript_correction_core/graph.py +0 -838
- cjm_transcript_correction_core-0.0.3/cjm_transcript_correction_core.egg-info/entry_points.txt +0 -2
- cjm_transcript_correction_core-0.0.3/cjm_transcript_correction_core.egg-info/requires.txt +0 -4
- cjm_transcript_correction_core-0.0.3/tests/test_graph.py +0 -180
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/LICENSE +0 -0
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/MANIFEST.in +0 -0
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/cjm_transcript_correction_core.egg-info/SOURCES.txt +0 -0
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/cjm_transcript_correction_core.egg-info/dependency_links.txt +0 -0
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/cjm_transcript_correction_core.egg-info/top_level.txt +0 -0
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/setup.cfg +0 -0
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/tests/test_cli.py +0 -0
- {cjm_transcript_correction_core-0.0.3 → cjm_transcript_correction_core-0.0.5}/tests/test_pipeline.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cjm-transcript-correction-core
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.5
|
|
4
4
|
Summary: A frontend-agnostic core for the transcript correction workflow — the first downstream graph-extension core; composes the graph-storage capability worker into a headless pipeline that applies unified, non-destructive corrections (text, punctuation, segmentation) as a supersede-able overlay on a committed decomposition spine, recomputes the review worklist from deterministic signals, and exposes a CLI as its first driver.
|
|
5
5
|
Author-email: "Christian J. Mills" <9126128+cj-mills@users.noreply.github.com>
|
|
6
6
|
License: Apache-2.0
|
|
@@ -10,9 +10,9 @@ Classifier: Programming Language :: Python :: 3 :: Only
|
|
|
10
10
|
Requires-Python: >=3.12
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
|
-
Requires-Dist: cjm_substrate>=0.0.
|
|
14
|
-
Requires-Dist: cjm_context_graph_primitives>=0.0.
|
|
15
|
-
Requires-Dist: cjm-context-graph-layer>=0.0.
|
|
13
|
+
Requires-Dist: cjm_substrate>=0.0.57
|
|
14
|
+
Requires-Dist: cjm_context_graph_primitives>=0.0.15
|
|
15
|
+
Requires-Dist: cjm-context-graph-layer>=0.0.11
|
|
16
16
|
Requires-Dist: cjm-transcript-graph-schema>=0.0.7
|
|
17
17
|
Dynamic: license-file
|
|
18
18
|
|
|
@@ -40,37 +40,67 @@ A frontend-agnostic core for the transcript correction workflow — the first do
|
|
|
40
40
|
- `main` _function_ — CLI entry point (console script: `cjm-transcript-correction-core`).
|
|
41
41
|
- `review_command` _function_ — Execute the `review` subcommand: interactive text corrections over the flagged worklist.
|
|
42
42
|
- `run_command` _function_ — Execute the `run` subcommand: correct a decomp manifest's committed spine.
|
|
43
|
+
- `stats_command` _function_ — Execute the `stats` subcommand: flywheel accounting over the shared graph.
|
|
43
44
|
|
|
44
45
|
### `cjm_transcript_correction_core.graph`
|
|
45
46
|
|
|
46
47
|
- `active_corrections` _function_ — Filter to the effective correction set (the layer's resolve_active over a read superseded set).
|
|
48
|
+
- `active_speaker_assignments` _function_ — Project the ACTIVE speaker assignment per segment (latest-wins).
|
|
49
|
+
- `aggregate_session_purposes` _function_ — Fold sessions into a per-source purpose mix (pure; d915d545 picker rung).
|
|
50
|
+
- `apply_chunk_inserts` _function_ — Synthesize inserted chunks into the effective spine (DEC 3d3fa2a8).
|
|
51
|
+
- `apply_time_nudges` _function_ — Apply timing corrections onto segment times (latest-wins per edge).
|
|
47
52
|
- `build_boundary_shift_correction` _function_ — Build a grouping Correction that moves text across one segment boundary.
|
|
53
|
+
- `build_chunk_insert_correction` _function_ — Build an insertion Correction that adds a chunk the skeleton never cut (DEC 3d3fa2a8).
|
|
54
|
+
- `build_chunk_split_corrections` _function_ — Compose a chunk SPLIT from the EXISTING verbs (work item 99c1d2ba) — no
|
|
48
55
|
- `build_correction_node` _function_ — Construct a Correction overlay node (pure; commit happens separately).
|
|
56
|
+
- `build_mark_correction` _function_ — Build a NON-MUTATING mark Correction (DEC 2a231843: routed attention).
|
|
49
57
|
- `build_prune_amendment` _function_ — Build a grouping Correction that supersedes a prune with a REDUCED set (unprune).
|
|
50
58
|
- `build_prune_correction` _function_ — Build one batch grouping Correction that prunes empty segments (D14).
|
|
51
59
|
- `build_reject_review` _function_ — Build a review Correction that REJECTS a prior correction (reject-as-supersede).
|
|
60
|
+
- `build_speaker_assign_correction` _function_ — Build a speaker Correction — the assignment op envelope (DEC d6df3a8e).
|
|
52
61
|
- `build_text_correction` _function_ — Build a text_content Correction + its CORRECTS (+ optional SUPERSEDES) edges.
|
|
62
|
+
- `build_time_nudge_correction` _function_ — Build a timing Correction that nudges segment boundary TIMES (node + CORRECTS edges).
|
|
53
63
|
- `commit_boundary_shift_correction` _function_ — Commit a boundary-shift correction (node + CORRECTS x2 [+ SUPERSEDES]) + REVIEWED markers on both segments.
|
|
64
|
+
- `commit_chunk_insert_correction` _function_ — Commit a chunk insertion (node + CORRECTS per flank).
|
|
65
|
+
- `commit_chunk_insert_removal` _function_ — Remove an inserted chunk WITHOUT touching layer-0 (reject-as-supersede).
|
|
66
|
+
- `commit_chunk_split_correction` _function_ — Commit a chunk split: three composed nodes in ONE atomic batch + ONE journal op.
|
|
67
|
+
- `commit_chunk_split_removal` _function_ — UNSPLIT: remove a split's right half AND its whole group (one review
|
|
68
|
+
- `commit_mark_correction` _function_ — Commit a mark (node + CORRECTS per anchored segment [+ SUPERSEDES]).
|
|
69
|
+
- `commit_mark_dismissal` _function_ — Dismiss an open mark WITHOUT a correction (reject-as-supersede).
|
|
54
70
|
- `commit_nodes_edges` _function_ — Commit overlay nodes/edges through the layer's idempotent extend_graph.
|
|
55
71
|
- `commit_prune_amendment` _function_ — Commit an unprune amendment (node + DERIVED_FROM edges + SUPERSEDES).
|
|
72
|
+
- `commit_speaker_assign_correction` _function_ — Commit a speaker assignment (node + CORRECTS per segment + ASSIGNS).
|
|
73
|
+
- `commit_speaker_entity` _function_ — Mint a source-spanning Entity into the shared registry (DEC 4ec6a49c).
|
|
56
74
|
- `commit_text_correction` _function_ — Commit a text_content correction (node + CORRECTS [+ SUPERSEDES]) + a REVIEWED marker.
|
|
75
|
+
- `commit_time_nudge_correction` _function_ — Commit a time-nudge correction (node + CORRECTS per touched segment).
|
|
76
|
+
- `correction_stats` _function_ — Fold one Source's ACTIVE overlay into flywheel-accounting counts (pure).
|
|
57
77
|
- `corrections_to_edits` _function_ — Map this core's Correction payloads onto the layer's spine-edit vocabulary.
|
|
58
|
-
- `count_source_segments` _function_ — Count a Source's segments server-side under its chosen rendition (typed count mode).
|
|
78
|
+
- `count_source_segments` _function_ — Count a Source's segments server-side under its chosen rendition + skeleton (typed count mode).
|
|
59
79
|
- `find_active_text_correction` _function_ — Single-segment convenience over the batch read (cross-session; latest wins).
|
|
60
80
|
- `find_active_text_corrections_batch` _function_ — Active text corrections for MANY segments in TWO round-trips (C17).
|
|
81
|
+
- `find_chunk_split_group` _function_ — Resolve a split right-half's GROUP — the ac84360a group marker cashed in.
|
|
61
82
|
- `find_corrections_for_session` _function_ — List corrections recorded in a session (typed property filter).
|
|
62
83
|
- `find_prior_corrections_by_hash` _function_ — Cross-transcript correction-cache lookup (targeted; the graph IS the lexicon).
|
|
63
84
|
- `get_session` _function_ — Fetch a CorrectionSession node by id (resume/reopen) — typed get, dict shape preserved.
|
|
85
|
+
- `list_source_spines` _function_ — The SPINES coexisting under a Source's chosen rendition (DEC f1024568).
|
|
86
|
+
- `list_speaker_entities` _function_ — Read the source-spanning entity registry (the picker's registry tier).
|
|
64
87
|
- `load_empty_segments` _function_ — Load ONLY a Source's empty-text segments under its chosen rendition (D14 prune).
|
|
65
88
|
- `load_review_markers` _function_ — Load a session's review markers (typed edge projection over REVIEWED edges).
|
|
66
89
|
- `load_source_corrections` _function_ — Load every Correction targeting a Source (across sessions) + the superseded-id set.
|
|
67
|
-
- `load_source_segments` _function_ — Load a Source's fine Segment spine under its chosen rendition (typed query surface).
|
|
90
|
+
- `load_source_segments` _function_ — Load a Source's fine Segment spine under its chosen rendition + skeleton (typed query surface).
|
|
68
91
|
- `load_variant_texts` _function_ — Resolve per-transcriber chunk texts from the segments' CharSlice refs.
|
|
92
|
+
- `mark_anchor_segments` _function_ — Validate a mark anchor and list the Segment ids it touches.
|
|
93
|
+
- `open_marks` _function_ — Filter to the OPEN marks — the pass-2 worklist ('query open marks, walk them').
|
|
69
94
|
- `project_effective_spine` _function_ — Project the effective spine = layer-0 + applied corrections.
|
|
95
|
+
- `reanchor_span` _function_ — Re-locate a span anchor in text that may have been edited since mark time.
|
|
70
96
|
- `record_review_markers` _function_ — Persist per-(session, segment) review markers as REVIEWED edges.
|
|
97
|
+
- `rename_speaker_entity` _function_ — Rename an Entity on its STABLE id — identification IS a rename (DEC 484e2d74).
|
|
71
98
|
- `resolve_source_renditions` _function_ — Pick the AudioRendition set whose fine Segment spine correction operates on.
|
|
99
|
+
- `session_purposes_by_source` _function_ — Read every CorrectionSession once and fold the per-source purpose mix.
|
|
100
|
+
- `set_session_purpose` _function_ — Update a session's purpose + updated_at (the test-session hygiene tag, DEC c86714a4).
|
|
72
101
|
- `set_session_status` _function_ — Update a session's status + updated_at.
|
|
73
102
|
- `source_audio_segment_ids` _function_ — The Source's coarse spine (one small typed read; ordered by index).
|
|
103
|
+
- `spine_where_for` _function_ — Resolve a skeleton selector against the observed spine set (pure).
|
|
74
104
|
- `start_session` _function_ — Create + commit a new CorrectionSession node.
|
|
75
105
|
- `submit_and_wait` _function_ — Submit one capability job, wait for it, return its result (raise on failure).
|
|
76
106
|
|
|
@@ -87,6 +117,7 @@ A frontend-agnostic core for the transcript correction workflow — the first do
|
|
|
87
117
|
- `CorrectionManifest` _class_ — Durable record of one correction run (proto-bundle; chainable, CR-20).
|
|
88
118
|
- `CorrectionRelations` _class_ — Registry of edge types the correction overlay adds to the spine graph.
|
|
89
119
|
- `CorrectionSession` _class_ — A resumable, reopen-able correction review over one or more sources.
|
|
120
|
+
- `Entity` _class_ — A source-spanning identity in the shared entity substrate (DEC 4ec6a49c).
|
|
90
121
|
- `SpineSegment` _class_ — A committed layer-0 Segment loaded from the graph (read view).
|
|
91
122
|
- `WorklistItem` _class_ — One spine segment surfaced for review, with its deterministic Tier-1 flags.
|
|
92
123
|
- `new_run_id` _function_ — Generate a unique, sortable correction run id.
|
|
@@ -112,9 +143,10 @@ A frontend-agnostic core for the transcript correction workflow — the first do
|
|
|
112
143
|
- `fa_coverage_flags` _function_ — Flag segments whose forced-alignment coverage looks suspect (Tier-1).
|
|
113
144
|
- `levenshtein` _function_ — Levenshtein edit distance (pure, in-core; variant-clustering primitive).
|
|
114
145
|
- `phonetic_key` _function_ — Compute a coarse phonetic key for a word (groups like-sounding variants).
|
|
146
|
+
- `speaker_turn_proposals` _function_ — Dominant diarization cluster per segment — the assign lane's proposal paint.
|
|
115
147
|
- `variant_divergence` _function_ — Within-segment cross-transcriber divergence (stage 5: intra-graph).
|
|
116
148
|
|
|
117
149
|
## Dependencies
|
|
118
150
|
|
|
119
151
|
**Depends on:** `cjm-context-graph-layer`, `cjm-context-graph-primitives`, `cjm-substrate`, `cjm-transcript-graph-schema`
|
|
120
|
-
**Used by:** `cjm-transcript-correction-tui`
|
|
152
|
+
**Used by:** `cjm-transcript-correction-tui`, `cjm-workflow-hub-tui`
|
|
@@ -22,37 +22,67 @@ A frontend-agnostic core for the transcript correction workflow — the first do
|
|
|
22
22
|
- `main` _function_ — CLI entry point (console script: `cjm-transcript-correction-core`).
|
|
23
23
|
- `review_command` _function_ — Execute the `review` subcommand: interactive text corrections over the flagged worklist.
|
|
24
24
|
- `run_command` _function_ — Execute the `run` subcommand: correct a decomp manifest's committed spine.
|
|
25
|
+
- `stats_command` _function_ — Execute the `stats` subcommand: flywheel accounting over the shared graph.
|
|
25
26
|
|
|
26
27
|
### `cjm_transcript_correction_core.graph`
|
|
27
28
|
|
|
28
29
|
- `active_corrections` _function_ — Filter to the effective correction set (the layer's resolve_active over a read superseded set).
|
|
30
|
+
- `active_speaker_assignments` _function_ — Project the ACTIVE speaker assignment per segment (latest-wins).
|
|
31
|
+
- `aggregate_session_purposes` _function_ — Fold sessions into a per-source purpose mix (pure; d915d545 picker rung).
|
|
32
|
+
- `apply_chunk_inserts` _function_ — Synthesize inserted chunks into the effective spine (DEC 3d3fa2a8).
|
|
33
|
+
- `apply_time_nudges` _function_ — Apply timing corrections onto segment times (latest-wins per edge).
|
|
29
34
|
- `build_boundary_shift_correction` _function_ — Build a grouping Correction that moves text across one segment boundary.
|
|
35
|
+
- `build_chunk_insert_correction` _function_ — Build an insertion Correction that adds a chunk the skeleton never cut (DEC 3d3fa2a8).
|
|
36
|
+
- `build_chunk_split_corrections` _function_ — Compose a chunk SPLIT from the EXISTING verbs (work item 99c1d2ba) — no
|
|
30
37
|
- `build_correction_node` _function_ — Construct a Correction overlay node (pure; commit happens separately).
|
|
38
|
+
- `build_mark_correction` _function_ — Build a NON-MUTATING mark Correction (DEC 2a231843: routed attention).
|
|
31
39
|
- `build_prune_amendment` _function_ — Build a grouping Correction that supersedes a prune with a REDUCED set (unprune).
|
|
32
40
|
- `build_prune_correction` _function_ — Build one batch grouping Correction that prunes empty segments (D14).
|
|
33
41
|
- `build_reject_review` _function_ — Build a review Correction that REJECTS a prior correction (reject-as-supersede).
|
|
42
|
+
- `build_speaker_assign_correction` _function_ — Build a speaker Correction — the assignment op envelope (DEC d6df3a8e).
|
|
34
43
|
- `build_text_correction` _function_ — Build a text_content Correction + its CORRECTS (+ optional SUPERSEDES) edges.
|
|
44
|
+
- `build_time_nudge_correction` _function_ — Build a timing Correction that nudges segment boundary TIMES (node + CORRECTS edges).
|
|
35
45
|
- `commit_boundary_shift_correction` _function_ — Commit a boundary-shift correction (node + CORRECTS x2 [+ SUPERSEDES]) + REVIEWED markers on both segments.
|
|
46
|
+
- `commit_chunk_insert_correction` _function_ — Commit a chunk insertion (node + CORRECTS per flank).
|
|
47
|
+
- `commit_chunk_insert_removal` _function_ — Remove an inserted chunk WITHOUT touching layer-0 (reject-as-supersede).
|
|
48
|
+
- `commit_chunk_split_correction` _function_ — Commit a chunk split: three composed nodes in ONE atomic batch + ONE journal op.
|
|
49
|
+
- `commit_chunk_split_removal` _function_ — UNSPLIT: remove a split's right half AND its whole group (one review
|
|
50
|
+
- `commit_mark_correction` _function_ — Commit a mark (node + CORRECTS per anchored segment [+ SUPERSEDES]).
|
|
51
|
+
- `commit_mark_dismissal` _function_ — Dismiss an open mark WITHOUT a correction (reject-as-supersede).
|
|
36
52
|
- `commit_nodes_edges` _function_ — Commit overlay nodes/edges through the layer's idempotent extend_graph.
|
|
37
53
|
- `commit_prune_amendment` _function_ — Commit an unprune amendment (node + DERIVED_FROM edges + SUPERSEDES).
|
|
54
|
+
- `commit_speaker_assign_correction` _function_ — Commit a speaker assignment (node + CORRECTS per segment + ASSIGNS).
|
|
55
|
+
- `commit_speaker_entity` _function_ — Mint a source-spanning Entity into the shared registry (DEC 4ec6a49c).
|
|
38
56
|
- `commit_text_correction` _function_ — Commit a text_content correction (node + CORRECTS [+ SUPERSEDES]) + a REVIEWED marker.
|
|
57
|
+
- `commit_time_nudge_correction` _function_ — Commit a time-nudge correction (node + CORRECTS per touched segment).
|
|
58
|
+
- `correction_stats` _function_ — Fold one Source's ACTIVE overlay into flywheel-accounting counts (pure).
|
|
39
59
|
- `corrections_to_edits` _function_ — Map this core's Correction payloads onto the layer's spine-edit vocabulary.
|
|
40
|
-
- `count_source_segments` _function_ — Count a Source's segments server-side under its chosen rendition (typed count mode).
|
|
60
|
+
- `count_source_segments` _function_ — Count a Source's segments server-side under its chosen rendition + skeleton (typed count mode).
|
|
41
61
|
- `find_active_text_correction` _function_ — Single-segment convenience over the batch read (cross-session; latest wins).
|
|
42
62
|
- `find_active_text_corrections_batch` _function_ — Active text corrections for MANY segments in TWO round-trips (C17).
|
|
63
|
+
- `find_chunk_split_group` _function_ — Resolve a split right-half's GROUP — the ac84360a group marker cashed in.
|
|
43
64
|
- `find_corrections_for_session` _function_ — List corrections recorded in a session (typed property filter).
|
|
44
65
|
- `find_prior_corrections_by_hash` _function_ — Cross-transcript correction-cache lookup (targeted; the graph IS the lexicon).
|
|
45
66
|
- `get_session` _function_ — Fetch a CorrectionSession node by id (resume/reopen) — typed get, dict shape preserved.
|
|
67
|
+
- `list_source_spines` _function_ — The SPINES coexisting under a Source's chosen rendition (DEC f1024568).
|
|
68
|
+
- `list_speaker_entities` _function_ — Read the source-spanning entity registry (the picker's registry tier).
|
|
46
69
|
- `load_empty_segments` _function_ — Load ONLY a Source's empty-text segments under its chosen rendition (D14 prune).
|
|
47
70
|
- `load_review_markers` _function_ — Load a session's review markers (typed edge projection over REVIEWED edges).
|
|
48
71
|
- `load_source_corrections` _function_ — Load every Correction targeting a Source (across sessions) + the superseded-id set.
|
|
49
|
-
- `load_source_segments` _function_ — Load a Source's fine Segment spine under its chosen rendition (typed query surface).
|
|
72
|
+
- `load_source_segments` _function_ — Load a Source's fine Segment spine under its chosen rendition + skeleton (typed query surface).
|
|
50
73
|
- `load_variant_texts` _function_ — Resolve per-transcriber chunk texts from the segments' CharSlice refs.
|
|
74
|
+
- `mark_anchor_segments` _function_ — Validate a mark anchor and list the Segment ids it touches.
|
|
75
|
+
- `open_marks` _function_ — Filter to the OPEN marks — the pass-2 worklist ('query open marks, walk them').
|
|
51
76
|
- `project_effective_spine` _function_ — Project the effective spine = layer-0 + applied corrections.
|
|
77
|
+
- `reanchor_span` _function_ — Re-locate a span anchor in text that may have been edited since mark time.
|
|
52
78
|
- `record_review_markers` _function_ — Persist per-(session, segment) review markers as REVIEWED edges.
|
|
79
|
+
- `rename_speaker_entity` _function_ — Rename an Entity on its STABLE id — identification IS a rename (DEC 484e2d74).
|
|
53
80
|
- `resolve_source_renditions` _function_ — Pick the AudioRendition set whose fine Segment spine correction operates on.
|
|
81
|
+
- `session_purposes_by_source` _function_ — Read every CorrectionSession once and fold the per-source purpose mix.
|
|
82
|
+
- `set_session_purpose` _function_ — Update a session's purpose + updated_at (the test-session hygiene tag, DEC c86714a4).
|
|
54
83
|
- `set_session_status` _function_ — Update a session's status + updated_at.
|
|
55
84
|
- `source_audio_segment_ids` _function_ — The Source's coarse spine (one small typed read; ordered by index).
|
|
85
|
+
- `spine_where_for` _function_ — Resolve a skeleton selector against the observed spine set (pure).
|
|
56
86
|
- `start_session` _function_ — Create + commit a new CorrectionSession node.
|
|
57
87
|
- `submit_and_wait` _function_ — Submit one capability job, wait for it, return its result (raise on failure).
|
|
58
88
|
|
|
@@ -69,6 +99,7 @@ A frontend-agnostic core for the transcript correction workflow — the first do
|
|
|
69
99
|
- `CorrectionManifest` _class_ — Durable record of one correction run (proto-bundle; chainable, CR-20).
|
|
70
100
|
- `CorrectionRelations` _class_ — Registry of edge types the correction overlay adds to the spine graph.
|
|
71
101
|
- `CorrectionSession` _class_ — A resumable, reopen-able correction review over one or more sources.
|
|
102
|
+
- `Entity` _class_ — A source-spanning identity in the shared entity substrate (DEC 4ec6a49c).
|
|
72
103
|
- `SpineSegment` _class_ — A committed layer-0 Segment loaded from the graph (read view).
|
|
73
104
|
- `WorklistItem` _class_ — One spine segment surfaced for review, with its deterministic Tier-1 flags.
|
|
74
105
|
- `new_run_id` _function_ — Generate a unique, sortable correction run id.
|
|
@@ -94,9 +125,10 @@ A frontend-agnostic core for the transcript correction workflow — the first do
|
|
|
94
125
|
- `fa_coverage_flags` _function_ — Flag segments whose forced-alignment coverage looks suspect (Tier-1).
|
|
95
126
|
- `levenshtein` _function_ — Levenshtein edit distance (pure, in-core; variant-clustering primitive).
|
|
96
127
|
- `phonetic_key` _function_ — Compute a coarse phonetic key for a word (groups like-sounding variants).
|
|
128
|
+
- `speaker_turn_proposals` _function_ — Dominant diarization cluster per segment — the assign lane's proposal paint.
|
|
97
129
|
- `variant_divergence` _function_ — Within-segment cross-transcriber divergence (stage 5: intra-graph).
|
|
98
130
|
|
|
99
131
|
## Dependencies
|
|
100
132
|
|
|
101
133
|
**Depends on:** `cjm-context-graph-layer`, `cjm-context-graph-primitives`, `cjm-substrate`, `cjm-transcript-graph-schema`
|
|
102
|
-
**Used by:** `cjm-transcript-correction-tui`
|
|
134
|
+
**Used by:** `cjm-transcript-correction-tui`, `cjm-workflow-hub-tui`
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.0.5"
|
|
@@ -3,11 +3,16 @@
|
|
|
3
3
|
import argparse
|
|
4
4
|
import asyncio
|
|
5
5
|
import logging
|
|
6
|
+
import os
|
|
6
7
|
from pathlib import Path
|
|
7
8
|
from typing import Dict, List, Optional
|
|
8
9
|
|
|
10
|
+
from cjm_context_graph_layer.ops import graph_task
|
|
11
|
+
from cjm_context_graph_primitives.query import NodeQuery
|
|
9
12
|
from cjm_substrate.core.manager import CapabilityManager
|
|
10
13
|
from cjm_substrate.core.queue import JobQueue
|
|
14
|
+
from cjm_substrate.core.workspace import resolve_workspace
|
|
15
|
+
from cjm_transcript_correction_core.graph import correction_stats, load_source_corrections
|
|
11
16
|
from cjm_transcript_correction_core.models import CorrectionConfig
|
|
12
17
|
from cjm_transcript_correction_core.pipeline import (load_decomp_manifest, resolve_graph_db_path,
|
|
13
18
|
run_correction, run_review)
|
|
@@ -18,7 +23,13 @@ logger = logging.getLogger(__name__)
|
|
|
18
23
|
def _add_common_run_args(p: argparse.ArgumentParser) -> None: # Shared run/review arguments
|
|
19
24
|
"""Attach the capability / session / output arguments shared by `run` and `review`."""
|
|
20
25
|
p.add_argument("manifest", help="Decomp-core run manifest JSON (the committed spine)")
|
|
21
|
-
p.add_argument("--manifests-dir", default=
|
|
26
|
+
p.add_argument("--manifests-dir", default=None,
|
|
27
|
+
help="Capability manifests directory (default: the workspace's .cjm/manifests "
|
|
28
|
+
"when one is active, else .cjm/manifests under the cwd)")
|
|
29
|
+
p.add_argument("--workspace", default=None,
|
|
30
|
+
help="Workspace root (5daadfc4; default: CJM_WORKSPACE env, else upward walk "
|
|
31
|
+
"from cwd). Supplies manifests/output defaults and is exported so "
|
|
32
|
+
"capability workers resolve workspace-scoped paths")
|
|
22
33
|
p.add_argument("--graph-capability", default="cjm-capability-graph-sqlite", help="Graph-storage capability name")
|
|
23
34
|
p.add_argument("--graph-db-path", default=None,
|
|
24
35
|
help="Override graph DB path (default: the decomp manifest's recorded db_path)")
|
|
@@ -26,12 +37,18 @@ def _add_common_run_args(p: argparse.ArgumentParser) -> None: # Shared run/revi
|
|
|
26
37
|
help="Which AudioRendition spine to correct when a source has more than one "
|
|
27
38
|
"(\"raw\" or a preprocessing substring e.g. \"demucs\"); default: auto-select the "
|
|
28
39
|
"decomposed one (errors if ambiguous)")
|
|
40
|
+
p.add_argument("--skeleton", default=None,
|
|
41
|
+
help="Which SKELETON spine to correct when several coexist under one rendition "
|
|
42
|
+
"(sentence-split, DEC f1024568): \"legacy\" = the pre-split spine, or a "
|
|
43
|
+
"skeleton-hash prefix; default: auto (errors when >1 coexist)")
|
|
29
44
|
p.add_argument("--sysmon-capability", default=None,
|
|
30
45
|
help="monitor for empirical attribution (CR-7); loaded first; default: none")
|
|
31
46
|
p.add_argument("--session", default=None, help="Resume an existing CorrectionSession id")
|
|
32
47
|
p.add_argument("--reopen", action="store_true", help="Reopen a completed session (with --session)")
|
|
33
48
|
p.add_argument("--actor", default="human", help="Actor recorded on corrections + review markers")
|
|
34
|
-
p.add_argument("--output", default=None,
|
|
49
|
+
p.add_argument("--output", default=None,
|
|
50
|
+
help="Correction-manifest output path (default: <workspace>/runs/<run_id>.json "
|
|
51
|
+
"when a workspace is active, else runs/<run_id>.json under the cwd)")
|
|
35
52
|
p.add_argument("-v", "--verbose", action="store_true", help="DEBUG-level logging")
|
|
36
53
|
|
|
37
54
|
|
|
@@ -56,6 +73,26 @@ def build_parser() -> argparse.ArgumentParser: # Configured CLI parser
|
|
|
56
73
|
_add_common_run_args(review)
|
|
57
74
|
review.add_argument("--review-max", type=int, default=0, help="Max worklist items to review (0 = all)")
|
|
58
75
|
review.add_argument("-y", "--yes", action="store_true", help="Auto-mark every reviewed item (no edits)")
|
|
76
|
+
|
|
77
|
+
stats = sub.add_parser(
|
|
78
|
+
"stats", help="Flywheel accounting: active labeled spans / open marks / op counts per source")
|
|
79
|
+
stats.add_argument("--manifests-dir", default=None,
|
|
80
|
+
help="Capability manifests directory (default: the workspace's .cjm/manifests "
|
|
81
|
+
"when one is active, else .cjm/manifests under the cwd)")
|
|
82
|
+
stats.add_argument("--workspace", default=None,
|
|
83
|
+
help="Workspace root (default: CJM_WORKSPACE env, else upward walk from cwd)")
|
|
84
|
+
stats.add_argument("--graph-capability", default="cjm-capability-graph-sqlite",
|
|
85
|
+
help="Graph-storage capability name")
|
|
86
|
+
stats.add_argument("--graph-db-path", default=None,
|
|
87
|
+
help="Graph db path (default: the capability's persisted workspace config)")
|
|
88
|
+
stats.add_argument("--source", default=None,
|
|
89
|
+
help="Source node id or title substring (default: every Source)")
|
|
90
|
+
stats.add_argument("--label", default=None,
|
|
91
|
+
help="Spotlight one label/class (e.g. inhale): prints its insert+mark grand total")
|
|
92
|
+
stats.add_argument("--genuine-only", action="store_true",
|
|
93
|
+
help="Count only corrections from GENUINE sessions (purpose unset/genuine — "
|
|
94
|
+
"feature-test noise excluded, DEC c86714a4); supersession stays global")
|
|
95
|
+
stats.add_argument("-v", "--verbose", action="store_true", help="DEBUG-level logging")
|
|
59
96
|
return parser
|
|
60
97
|
|
|
61
98
|
|
|
@@ -84,6 +121,14 @@ async def run_command(
|
|
|
84
121
|
args: argparse.Namespace, # Parsed args for the `run` subcommand
|
|
85
122
|
) -> int: # Process exit code
|
|
86
123
|
"""Execute the `run` subcommand: correct a decomp manifest's committed spine."""
|
|
124
|
+
# 5daadfc4 workspace: resolve BEFORE any substrate config loads; export so
|
|
125
|
+
# the process tree (substrate config, capability workers) is workspace-scoped.
|
|
126
|
+
ws = resolve_workspace(explicit=getattr(args, "workspace", None))
|
|
127
|
+
if ws is not None:
|
|
128
|
+
os.environ["CJM_WORKSPACE"] = str(ws.root)
|
|
129
|
+
if args.manifests_dir is None:
|
|
130
|
+
args.manifests_dir = (str(ws.substrate_data_dir / "manifests")
|
|
131
|
+
if ws is not None else ".cjm/manifests")
|
|
87
132
|
manifest_path = str(Path(args.manifest).resolve())
|
|
88
133
|
if not Path(manifest_path).exists():
|
|
89
134
|
raise SystemExit(f"decomp manifest not found: {manifest_path}")
|
|
@@ -96,7 +141,7 @@ async def run_command(
|
|
|
96
141
|
cfg = CorrectionConfig(
|
|
97
142
|
graph_capability=args.graph_capability, graph_db_path=graph_db_path,
|
|
98
143
|
actor=args.actor, assume_yes=args.yes, prune_empty=not args.no_prune,
|
|
99
|
-
rendition_selector=args.rendition,
|
|
144
|
+
rendition_selector=args.rendition, skeleton_selector=args.skeleton,
|
|
100
145
|
)
|
|
101
146
|
|
|
102
147
|
manager = CapabilityManager(
|
|
@@ -122,8 +167,9 @@ async def run_command(
|
|
|
122
167
|
except Exception as e: # Best-effort teardown; never mask the run's outcome
|
|
123
168
|
logger.warning(f"unload {iid} failed: {e}")
|
|
124
169
|
|
|
125
|
-
out = Path(args.output) if args.output
|
|
126
|
-
|
|
170
|
+
out = (Path(args.output) if args.output
|
|
171
|
+
else (ws.runs_dir if ws is not None else Path("runs")) / f"{manifest.run_id}.json")
|
|
172
|
+
manifest.save(out, workspace=ws)
|
|
127
173
|
n_sources = len(manifest.sources)
|
|
128
174
|
n_pruned = sum(s.get("pruned", 0) for s in manifest.sources)
|
|
129
175
|
n_flagged = sum(s.get("worklist_flagged", 0) for s in manifest.sources)
|
|
@@ -137,6 +183,13 @@ async def review_command(
|
|
|
137
183
|
args: argparse.Namespace, # Parsed args for the `review` subcommand
|
|
138
184
|
) -> int: # Process exit code
|
|
139
185
|
"""Execute the `review` subcommand: interactive text corrections over the flagged worklist."""
|
|
186
|
+
# 5daadfc4 workspace: same early resolution + export as run_command.
|
|
187
|
+
ws = resolve_workspace(explicit=getattr(args, "workspace", None))
|
|
188
|
+
if ws is not None:
|
|
189
|
+
os.environ["CJM_WORKSPACE"] = str(ws.root)
|
|
190
|
+
if args.manifests_dir is None:
|
|
191
|
+
args.manifests_dir = (str(ws.substrate_data_dir / "manifests")
|
|
192
|
+
if ws is not None else ".cjm/manifests")
|
|
140
193
|
manifest_path = str(Path(args.manifest).resolve())
|
|
141
194
|
if not Path(manifest_path).exists():
|
|
142
195
|
raise SystemExit(f"decomp manifest not found: {manifest_path}")
|
|
@@ -147,7 +200,7 @@ async def review_command(
|
|
|
147
200
|
|
|
148
201
|
cfg = CorrectionConfig(graph_capability=args.graph_capability, graph_db_path=graph_db_path,
|
|
149
202
|
actor=args.actor, assume_yes=args.yes, prune_empty=False,
|
|
150
|
-
rendition_selector=args.rendition)
|
|
203
|
+
rendition_selector=args.rendition, skeleton_selector=args.skeleton)
|
|
151
204
|
manager = CapabilityManager(search_paths=[Path(args.manifests_dir)], sysmon_capability_name=args.sysmon_capability)
|
|
152
205
|
load_order = ([args.sysmon_capability] if args.sysmon_capability else []) + [cfg.graph_capability]
|
|
153
206
|
load_capabilities(manager, load_order, configs={cfg.graph_capability: {"db_path": graph_db_path}})
|
|
@@ -167,8 +220,9 @@ async def review_command(
|
|
|
167
220
|
except Exception as e: # Best-effort teardown; never mask the run's outcome
|
|
168
221
|
logger.warning(f"unload {iid} failed: {e}")
|
|
169
222
|
|
|
170
|
-
out = Path(args.output) if args.output
|
|
171
|
-
|
|
223
|
+
out = (Path(args.output) if args.output
|
|
224
|
+
else (ws.runs_dir if ws is not None else Path("runs")) / f"{manifest.run_id}.json")
|
|
225
|
+
manifest.save(out, workspace=ws)
|
|
172
226
|
n_corr = sum(s.get("corrected", 0) for s in manifest.sources)
|
|
173
227
|
n_active = sum(s.get("active_corrections", 0) for s in manifest.sources)
|
|
174
228
|
print(f"correction manifest: {out}")
|
|
@@ -190,4 +244,99 @@ def main(
|
|
|
190
244
|
return asyncio.run(run_command(args))
|
|
191
245
|
if args.command == "review":
|
|
192
246
|
return asyncio.run(review_command(args))
|
|
247
|
+
if args.command == "stats":
|
|
248
|
+
return asyncio.run(stats_command(args))
|
|
193
249
|
raise SystemExit(f"unknown command: {args.command}")
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
async def stats_command(
|
|
253
|
+
args: argparse.Namespace, # Parsed args for the `stats` subcommand
|
|
254
|
+
) -> int: # Process exit code
|
|
255
|
+
"""Execute the `stats` subcommand: flywheel accounting over the shared graph.
|
|
256
|
+
|
|
257
|
+
The manual-tally retirement (drive ask 2026-07-27): per Source, the ACTIVE
|
|
258
|
+
overlay folds into counts — labeled insert spans, split boundaries, open
|
|
259
|
+
marks by class, op totals — plus the session purpose mix so dev-noise is
|
|
260
|
+
visible; --genuine-only cuts the counts to genuine-session corrections
|
|
261
|
+
(the DEC c86714a4 tag), --label spotlights one class corpus-wide (the
|
|
262
|
+
"how many active inhale spans?" one-liner)."""
|
|
263
|
+
ws = resolve_workspace(explicit=getattr(args, "workspace", None))
|
|
264
|
+
if ws is not None:
|
|
265
|
+
os.environ["CJM_WORKSPACE"] = str(ws.root)
|
|
266
|
+
if args.manifests_dir is None:
|
|
267
|
+
args.manifests_dir = (str(ws.substrate_data_dir / "manifests")
|
|
268
|
+
if ws is not None else ".cjm/manifests")
|
|
269
|
+
manager = CapabilityManager(search_paths=[Path(args.manifests_dir)])
|
|
270
|
+
configs = ({args.graph_capability: {"db_path": args.graph_db_path}}
|
|
271
|
+
if args.graph_db_path else None)
|
|
272
|
+
load_capabilities(manager, [args.graph_capability], configs=configs)
|
|
273
|
+
queue = JobQueue(deps=manager)
|
|
274
|
+
await queue.start()
|
|
275
|
+
try:
|
|
276
|
+
res = await graph_task(queue, args.graph_capability, "query_nodes",
|
|
277
|
+
query=NodeQuery(label="Source", project=["title"]).to_dict())
|
|
278
|
+
sources = [(r["id"], str(r.get("title") or "")) for r in (res.rows or [])]
|
|
279
|
+
if args.source:
|
|
280
|
+
needle = args.source.lower()
|
|
281
|
+
sources = [(i, t) for i, t in sources
|
|
282
|
+
if i == args.source or needle in t.lower()]
|
|
283
|
+
if not sources:
|
|
284
|
+
print("no matching Source nodes")
|
|
285
|
+
return 1
|
|
286
|
+
sres = await graph_task(queue, args.graph_capability, "query_nodes",
|
|
287
|
+
query=NodeQuery(label="CorrectionSession").to_dict())
|
|
288
|
+
genuine_ids = set()
|
|
289
|
+
purpose_of: Dict[str, str] = {}
|
|
290
|
+
for n in (sres.nodes or []):
|
|
291
|
+
d = n.to_dict() if hasattr(n, "to_dict") else n
|
|
292
|
+
purpose = str((d.get("properties") or {}).get("purpose") or "genuine")
|
|
293
|
+
purpose_of[d["id"]] = purpose
|
|
294
|
+
if purpose == "genuine":
|
|
295
|
+
genuine_ids.add(d["id"])
|
|
296
|
+
totals: Dict[str, Dict[str, int]] = {"insert_labels": {}, "mark_classes": {}}
|
|
297
|
+
total_splits = 0
|
|
298
|
+
for sid, title in sources:
|
|
299
|
+
corrections, superseded = await load_source_corrections(
|
|
300
|
+
queue, args.graph_capability, sid)
|
|
301
|
+
counted = corrections
|
|
302
|
+
if args.genuine_only:
|
|
303
|
+
# Purpose scopes the COUNTS; the superseded set stays global —
|
|
304
|
+
# supersession is spine state whoever committed it.
|
|
305
|
+
counted = [c for c in corrections if c.get("session_id") in genuine_ids]
|
|
306
|
+
st = correction_stats(counted, superseded)
|
|
307
|
+
mix: Dict[str, int] = {}
|
|
308
|
+
for c in corrections:
|
|
309
|
+
p = purpose_of.get(str(c.get("session_id")), "genuine")
|
|
310
|
+
mix[p] = mix.get(p, 0) + 1
|
|
311
|
+
print(f"== {title or sid} ({sid}) ==")
|
|
312
|
+
print(" ops by session purpose: "
|
|
313
|
+
+ (" ".join(f"{k}x{v}" for k, v in sorted(mix.items())) or "none"))
|
|
314
|
+
print(f" active corrections: {st['active']} ("
|
|
315
|
+
+ (" ".join(f"{k}={v}" for k, v in sorted(st["ops"].items())) or "none") + ")")
|
|
316
|
+
print(f" splits: {st['splits']}")
|
|
317
|
+
print(" labeled inserts: "
|
|
318
|
+
+ (" · ".join(f"{k}x{v}" for k, v in sorted(st["insert_labels"].items())) or "none"))
|
|
319
|
+
print(f" open marks ({st['open_marks']}): "
|
|
320
|
+
+ (" · ".join(f"{k}x{v}" for k, v in sorted(st["mark_classes"].items())) or "none"))
|
|
321
|
+
total_splits += st["splits"]
|
|
322
|
+
for k, v in st["insert_labels"].items():
|
|
323
|
+
totals["insert_labels"][k] = totals["insert_labels"].get(k, 0) + v
|
|
324
|
+
for k, v in st["mark_classes"].items():
|
|
325
|
+
totals["mark_classes"][k] = totals["mark_classes"].get(k, 0) + v
|
|
326
|
+
print(f"== TOTALS ({len(sources)} source(s)) ==")
|
|
327
|
+
print(f" splits: {total_splits}")
|
|
328
|
+
print(" labeled inserts: "
|
|
329
|
+
+ (" · ".join(f"{k}x{v}" for k, v in sorted(totals["insert_labels"].items())) or "none"))
|
|
330
|
+
print(" open marks: "
|
|
331
|
+
+ (" · ".join(f"{k}x{v}" for k, v in sorted(totals["mark_classes"].items())) or "none"))
|
|
332
|
+
if args.label:
|
|
333
|
+
ins = totals["insert_labels"].get(args.label, 0)
|
|
334
|
+
mk = totals["mark_classes"].get(args.label, 0)
|
|
335
|
+
print(f" active {args.label!r} spans: {ins + mk} (inserts {ins} + marks {mk})")
|
|
336
|
+
finally:
|
|
337
|
+
await queue.stop()
|
|
338
|
+
try:
|
|
339
|
+
manager.unload_capability(args.graph_capability)
|
|
340
|
+
except Exception as e: # Best-effort teardown; never mask the stats outcome
|
|
341
|
+
logger.warning(f"unload {args.graph_capability} failed: {e}")
|
|
342
|
+
return 0
|