File size: 6,927 Bytes
03d531b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e07820e
03d531b
 
 
 
 
 
 
e07820e
 
 
03d531b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e07820e
 
03d531b
 
 
 
 
 
 
 
 
 
 
 
e07820e
 
 
03d531b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e07820e
03d531b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e07820e
 
 
03d531b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e07820e
03d531b
 
 
 
 
 
e07820e
 
 
 
 
 
 
 
 
03d531b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e07820e
 
 
03d531b
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# Architecture notes for supervised interactive extraction

## Required shift

Original extraction flow:

```text
audio β†’ pipeline β†’ result artifacts
```

Current interactive foundation:

```text
audio/cache β†’ immutable manifest/artifacts β†’ supervision_state.json β†’ reactive UI β†’ user constraints/events/suggestions
```

The current implementation keeps the batch extraction artifacts immutable. Interactive edits mutate `supervision_state.json`, then `supervised_export.py` can render those edits into a separate `supervised/` artifact tree. The original `manifest.json`, original sample WAVs, original MIDI/reconstruction, and original ZIP remain untouched.

## Implemented modules

| Module/file | Responsibility |
|---|---|
| `pipeline_runner.py` | Batch extraction, timing, manifests, review-hit WAV exports |
| `sample_extractor.py` | Audio analysis, classification, batch/online clustering, export helpers |
| `supervised_state.py` | Persistent semantic job state, constraints, events, confidence, suggestions, force-onset, restore, undo |
| `app.py` | FastAPI endpoints for batch jobs, supervised state mutations, force-onset, restore, and edited export |
| `supervised_export.py` | Converts semantic state into edited WAV/MIDI/reconstruction/ZIP artifacts under `supervised/` |
| `web/app.js` | Browser state rendering, review queue, cluster board, suggestions, actions |
| `web/index.html` | Workstation layout and interactive supervision panel |
| `web/styles.css` | Visual treatment for low confidence, suppression, locks, panels |

## Core entities as implemented

`supervised_state.py` stores JSON dictionaries equivalent to these shapes:

```ts
type Hit = {
  id: string;
  index: number;
  label: string;
  cluster_id: string;
  original_cluster_id: string;
  cluster_label: string;
  onset_sec: number;
  duration_ms: number;
  rms_energy: number;
  spectral_centroid_hz: number;
  file: string;
  is_representative: boolean;
  source: "detected" | "forced";
  suppressed: boolean;
  favorite: boolean;
  review_status: "unreviewed" | "accepted" | "favorite" | "suppressed";
  confidence: number;
  confidence_reasons: string[];
  explicit: boolean;
};

type Cluster = {
  id: string;
  label: string;
  classification: string;
  hit_ids: string[];
  representative_hit_id: string | null;
  locked: boolean;
  user_named: boolean;
  confidence: number;
  confidence_reasons: string[];
  suppressed_count: number;
  original_id: string | null;
};

type Constraint =
  | { id: string; type: "must-link"; a: string; b: string; source: string }
  | { id: string; type: "cannot-link"; a: string; b: string; source: string }
  | { id: string; type: "force-cluster"; hit_id: string; cluster_id: string; source: string }
  | { id: string; type: "lock-cluster"; cluster_id: string; locked: boolean; source: string }
  | { id: string; type: "suppress-pattern"; example_hit_id: string; reason: string; source: string }
  | { id: string; type: "pin-representative"; hit_id: string; cluster_id: string; source: string };
```

## Current state file

Each completed run now gets:

```text
.runs/<job_id>/output/manifest.json
.runs/<job_id>/output/supervision_state.json
.runs/<job_id>/output/supervised/manifest.json        # after edited export
.runs/<job_id>/output/supervised/sample-pack.zip      # after edited export
```

`manifest.json` is the immutable batch result. `supervision_state.json` is the mutable, replayable semantic state.

## Implemented API additions

```text
GET    /api/jobs/{job_id}/state
POST   /api/jobs/{job_id}/hits/{hit_id}/move
POST   /api/jobs/{job_id}/hits/{hit_id}/pull-out
POST   /api/jobs/{job_id}/hits/{hit_id}/suppress
POST   /api/jobs/{job_id}/hits/{hit_id}/review
POST   /api/jobs/{job_id}/hits/{hit_id}/restore
POST   /api/jobs/{job_id}/hits/force-onset
POST   /api/jobs/{job_id}/export
POST   /api/jobs/{job_id}/clusters/{cluster_id}/lock
GET    /api/jobs/{job_id}/suggestions
POST   /api/jobs/{job_id}/suggestions/{suggestion_id}/accept
POST   /api/jobs/{job_id}/suggestions/{suggestion_id}/reject
GET    /api/jobs/{job_id}/explain/cluster/{cluster_id}
POST   /api/jobs/{job_id}/undo
```

## Current confidence scoring

Initial confidence is heuristic and deterministic. It combines:

- cluster size,
- cluster label purity,
- representative presence,
- lock state,
- hit label agreement with cluster label,
- energy rank,
- rough duration reasonableness,
- representative/favorite/explicit assignment state,
- suppression state.

This is good enough to drive the review queue but should be replaced or supplemented by cached feature-vector margins.

## Current suggestion engine

Implemented suggestion types:

```ts
type Suggestion =
  | { type: "move-hits"; hit_ids: string[]; target_cluster_id: string; confidence: number; reason: string }
  | { type: "split-hits"; hit_ids: string[]; source_cluster_id: string; target_cluster_id: string; confidence: number; reason: string }
  | { type: "suppress-hits"; hit_ids: string[]; confidence: number; reason: string };
```

Suggestion generation currently uses label, spectral centroid, and RMS-energy similarity. Open suggestions include exact `diff` previews showing affected hits and cluster counts before/after. Accepted suggestions become explicit constraints/examples.

## Event log

Examples now emitted:

```text
job.state.created
constraint.created
hit.moved
hit.pulled_out
cluster.locked
cluster.unlocked
hit.suppressed
hit.reviewed
suggestion.created
suggestion.accepted
suggestion.rejected
state.undo
hit.force_onset
hit.restored
supervised.exported
```

The UI renders recent events and constraints in the supervision panel.

## Local recomputation boundary

Implemented now:

```text
semantic edit
β†’ update hit/cluster membership in supervision_state.json
β†’ append constraints/events
β†’ generate heuristic suggestions
β†’ recompute hit/cluster confidence and review queue
```

Still not implemented:

```text
semantic edit
β†’ load cached feature vectors
β†’ choose affected neighborhood
β†’ run constrained local reclustering
β†’ update suggestion/recluster preview from real feature margins
```

Implemented now:

```text
semantic edit
β†’ export supervised state
β†’ write edited WAV/MIDI/reconstruction/ZIP under supervised/
```

## UI state implications

Implemented panels:

- waveform + onset audition,
- representative samples,
- detected hit review,
- outlier-first review queue,
- cluster board,
- suggestion inbox,
- constraint/history inspector,
- cluster explanation drawer,
- export/download panel for the original batch run.

Still missing:

- cluster merge/relabel/split controls,
- edited-vs-original comparison view,
- cached feature-neighborhood local reclustering.

## Implementation warning

Automatic propagation must stay conservative. The current implementation follows this by creating suggestions rather than silently moving/suppressing batches. Every semantic edit is undoable.