Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
655bba9
first draft of a health system
dadukhankevin Jan 20, 2026
06602e3
better UI and calculation
dadukhankevin Jan 20, 2026
5bcb0df
feature flag, improved UI
dadukhankevin Jan 27, 2026
fe10f1b
fix: complete merge of health system with main branch features
dadukhankevin Jan 31, 2026
69372ee
feat: enhance audio validation with health indicators
ryderwishart Feb 4, 2026
02a2368
Merge branch 'main' into daniel/health_system
ryderwishart Feb 4, 2026
9cb1d32
Clean up logging
ryderwishart Feb 4, 2026
23359cc
Enhance validation components with improved logging and state management
ryderwishart Feb 4, 2026
6b07d34
Implement health indicators and enhance logging in CodexCellEditor
ryderwishart Feb 4, 2026
02eb28e
Merge branch 'main' into daniel/health_system
ryderwishart Feb 6, 2026
4981431
Add new message type for health indicators in EditorReceiveMessages
ryderwishart Feb 6, 2026
05a3b8a
first draft of a health system
dadukhankevin Jan 20, 2026
cae27b0
better UI and calculation
dadukhankevin Jan 20, 2026
2e74994
feature flag, improved UI
dadukhankevin Jan 27, 2026
206857a
fix: complete merge of health system with main branch features
dadukhankevin Jan 31, 2026
75e4b09
feat: enhance audio validation with health indicators
ryderwishart Feb 4, 2026
0f698ad
Clean up logging
ryderwishart Feb 4, 2026
3c2e7dd
Enhance validation components with improved logging and state management
ryderwishart Feb 4, 2026
e752a18
Implement health indicators and enhance logging in CodexCellEditor
ryderwishart Feb 4, 2026
3bb446c
Add new message type for health indicators in EditorReceiveMessages
ryderwishart Feb 6, 2026
79b1a45
merge and fix backfill
dadukhankevin Feb 11, 2026
d14d134
fixed type issue leftover from merge
dadukhankevin Feb 11, 2026
376935d
Merge branch 'daniel/health_system' of https://github.com/genesis-ai-…
ryderwishart Feb 13, 2026
72fefe6
Resolve merge conflicts between health_system and main
dadukhankevin Feb 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,11 @@
"default": "",
"description": "Name of the project"
},
"codex-project-manager.showHealthIndicators": {
"type": "boolean",
"default": false,
"description": "Show health indicators for translation cells and files"
},
"codex-project-manager.validationCount": {
"type": "integer",
"default": 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const debug = (message: string, ...args: any[]) => {
};

// Schema version for migrations
export const CURRENT_SCHEMA_VERSION = 12; // Added milestone_index column for O(1) milestone lookup
export const CURRENT_SCHEMA_VERSION = 12; // Added milestone_index and t_health columns

export class SQLiteIndexManager {
private sql: SqlJsStatic | null = null;
Expand Down Expand Up @@ -302,10 +302,13 @@ export class SQLiteIndexManager {
t_audio_validation_count INTEGER DEFAULT 0,
t_audio_validated_by TEXT,
t_audio_is_fully_validated BOOLEAN DEFAULT FALSE,

-- Milestone index for O(1) lookup (0-based milestone index, NULL if no milestone)
milestone_index INTEGER,


-- Health score for translation quality (0.0-1.0, default 0.3 for unverified)
t_health REAL DEFAULT 0.3,

FOREIGN KEY (s_file_id) REFERENCES files(id) ON DELETE SET NULL,
FOREIGN KEY (t_file_id) REFERENCES files(id) ON DELETE SET NULL
)
Expand Down Expand Up @@ -866,15 +869,16 @@ export class SQLiteIndexManager {
// Add target-specific metadata columns
if (cellType === 'target') {
columns.push('t_current_edit_timestamp', 't_validation_count', 't_validated_by', 't_is_fully_validated',
't_audio_validation_count', 't_audio_validated_by', 't_audio_is_fully_validated');
't_audio_validation_count', 't_audio_validated_by', 't_audio_is_fully_validated', 't_health');
values.push(
actualEditTimestamp, // Only t_current_edit_timestamp for target cells (no redundant t_updated_at)
extractedMetadata.validationCount || 0,
extractedMetadata.validatedBy || null,
extractedMetadata.isFullyValidated ? 1 : 0,
extractedMetadata.audioValidationCount || 0,
extractedMetadata.audioValidatedBy || null,
extractedMetadata.audioIsFullyValidated ? 1 : 0
extractedMetadata.audioIsFullyValidated ? 1 : 0,
extractedMetadata.health ?? 0.3
);
}

Expand Down Expand Up @@ -1034,15 +1038,16 @@ export class SQLiteIndexManager {
// Add target-specific metadata columns
if (cellType === 'target') {
columns.push('t_current_edit_timestamp', 't_validation_count', 't_validated_by', 't_is_fully_validated',
't_audio_validation_count', 't_audio_validated_by', 't_audio_is_fully_validated');
't_audio_validation_count', 't_audio_validated_by', 't_audio_is_fully_validated', 't_health');
values.push(
actualEditTimestamp, // Only t_current_edit_timestamp for target cells (no redundant t_updated_at)
extractedMetadata.validationCount || 0,
extractedMetadata.validatedBy || null,
extractedMetadata.isFullyValidated ? 1 : 0,
extractedMetadata.audioValidationCount || 0,
extractedMetadata.audioValidatedBy || null,
extractedMetadata.audioIsFullyValidated ? 1 : 0
extractedMetadata.audioIsFullyValidated ? 1 : 0,
extractedMetadata.health ?? 0.3
);
}

Expand Down Expand Up @@ -1596,6 +1601,33 @@ export class SQLiteIndexManager {
return null;
}

// Get health values for multiple cells
async getCellsHealth(cellIds: string[]): Promise<Map<string, number>> {
if (!this.db || cellIds.length === 0) return new Map();

const placeholders = cellIds.map(() => '?').join(',');
const stmt = this.db.prepare(`
SELECT cell_id, t_health
FROM cells
WHERE cell_id IN (${placeholders})
`);

const result = new Map<string, number>();
try {
stmt.bind(cellIds);
while (stmt.step()) {
const row = stmt.getAsObject() as { cell_id: string; t_health: number | null; };
const health = row.t_health ?? 0.3;
result.set(row.cell_id, health);
console.log(`[SQLiteIndex] getCellsHealth: ${row.cell_id} -> ${health} (raw: ${row.t_health})`);
}
} finally {
stmt.free();
}
console.log(`[SQLiteIndex] getCellsHealth: queried ${cellIds.length} cells, found ${result.size}`);
return result;
}

// Get translation pair by cell ID
async getTranslationPair(cellId: string): Promise<any | null> {
if (!this.db) return null;
Expand Down Expand Up @@ -3582,6 +3614,7 @@ export class SQLiteIndexManager {
audioValidationCount?: number;
audioValidatedBy?: string;
audioIsFullyValidated?: boolean;
health?: number;
} {
const result: {
currentEditTimestamp?: number | null;
Expand All @@ -3591,6 +3624,7 @@ export class SQLiteIndexManager {
audioValidationCount?: number;
audioValidatedBy?: string;
audioIsFullyValidated?: boolean;
health?: number;
} = {};

if (!metadata || typeof metadata !== "object" || cellType !== "target") {
Expand Down Expand Up @@ -3645,6 +3679,13 @@ export class SQLiteIndexManager {
result.currentEditTimestamp = audioDetails.latestTimestamp;
}

// Extract health from metadata (if set)
// Health is optional - if not present, it will default to 0.3 when used
if (typeof metadata.health === 'number') {
result.health = metadata.health;
}
// No need to log when health is missing - it's expected for cells without health scores

return result;
}

Expand Down
87 changes: 80 additions & 7 deletions src/providers/codexCellEditorProvider/codexCellEditorProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
isMatchingFilePair as isMatchingFilePairUtil,
} from "../../utils/fileTypeUtils";
import { getCorrespondingSourceUri } from "../../utils/codexNotebookUtils";
import { getSQLiteIndexManager } from "../../activationHelpers/contextAware/contentIndexes/indexes/sqliteIndexManager";

// Enable debug logging if needed
const DEBUG_MODE = false;
Expand Down Expand Up @@ -293,6 +294,18 @@ export class CodexCellEditorProvider implements vscode.CustomEditorProvider<Code
});
});
}

if (e.affectsConfiguration("codex-project-manager.showHealthIndicators")) {
// Send updated health indicators setting to all webviews
const config = vscode.workspace.getConfiguration("codex-project-manager");
const showHealthIndicators = config.get<boolean>("showHealthIndicators", false);
this.webviewPanels.forEach((panel) => {
this.postMessageToWebview(panel, {
type: "updateShowHealthIndicators",
showHealthIndicators: showHealthIndicators,
});
});
}
});

this.context.subscriptions.push(configurationChangeDisposable);
Expand Down Expand Up @@ -856,6 +869,11 @@ export class CodexCellEditorProvider implements vscode.CustomEditorProvider<Code
debug("Could not fetch user role:", error);
}

// Get health indicator setting
const showHealthIndicators = vscode.workspace
.getConfiguration("codex-project-manager")
.get<boolean>("showHealthIndicators", false);

this.postMessageToWebview(webviewPanel, {
type: "providerSendsInitialContentPaginated",
rev,
Expand All @@ -870,6 +888,7 @@ export class CodexCellEditorProvider implements vscode.CustomEditorProvider<Code
validationCountAudio: validationCountAudio,
isAuthenticated: isAuthenticated,
userAccessLevel: userAccessLevel,
showHealthIndicators: showHealthIndicators,
});

// Record the initial position so subsequent updateWebview() calls
Expand Down Expand Up @@ -1090,6 +1109,16 @@ export class CodexCellEditorProvider implements vscode.CustomEditorProvider<Code
const docUri = document.uri.toString();
const rev = this.bumpDocumentRevision(docUri);

// Debug: log all document change events to see what's happening
if (e.edits && e.edits.length > 0) {
console.log("[CodexCellEditorProvider] Document change event:", {
editType: e.edits[0].type,
cellId: e.edits[0].cellId,
hasHealth: "health" in e.edits[0],
health: (e.edits[0] as any).health,
});
}

// Check if this is a validation update
if (e.edits && e.edits.length > 0 && e.edits[0].type === "validation") {
// Broadcast the validation update to all webviews for this document
Expand All @@ -1098,18 +1127,28 @@ export class CodexCellEditorProvider implements vscode.CustomEditorProvider<Code
content: {
cellId: e.edits[0].cellId,
validatedBy: e.edits[0].validatedBy,
health: (e.edits[0] as any).health,
},
};

console.log("[CodexCellEditorProvider] 📤 Sending providerUpdatesValidationState:", {
cellId: validationUpdate.content.cellId,
validatedByCount: validationUpdate.content.validatedBy?.length || 0,
health: validationUpdate.content.health,
validatedBy: validationUpdate.content.validatedBy,
});

// Send to all webviews that have this document open
this.webviewPanels.forEach((panel, docUri) => {
if (docUri === document.uri.toString()) {
safePostMessageToPanel(panel, validationUpdate);
const sent = safePostMessageToPanel(panel, validationUpdate);
console.log("[CodexCellEditorProvider] Message sent:", sent, "to panel:", docUri);
}
});

// Still update the current webview with the full content
updateWebview();
// Note: Don't call updateWebview() here - the targeted validation message
// already includes health, and a full refresh would cause a race condition
// that overwrites the health update
} else if (e.edits && e.edits.length > 0 && e.edits[0].type === "audioValidation") {
const selectedAudioId = document.getExplicitAudioSelection(e.edits[0].cellId) ?? undefined;
// Broadcast the audio validation update to all webviews for this document
Expand All @@ -1119,6 +1158,7 @@ export class CodexCellEditorProvider implements vscode.CustomEditorProvider<Code
cellId: e.edits[0].cellId,
validatedBy: e.edits[0].validatedBy,
selectedAudioId,
health: (e.edits[0] as any).health,
},
};

Expand All @@ -1129,8 +1169,9 @@ export class CodexCellEditorProvider implements vscode.CustomEditorProvider<Code
}
});

// Still update the current webview with the full content
updateWebview();
// Note: Don't call updateWebview() here - the targeted validation message
// already includes health, and a full refresh would cause a race condition
// that overwrites the health update
} else {
// Check if this is a paratext cell addition
debug("Document change event", { edits: e.edits, firstEdit: e.edits?.[0] });
Expand Down Expand Up @@ -2283,6 +2324,7 @@ export class CodexCellEditorProvider implements vscode.CustomEditorProvider<Code
selectedAudioId: cell.metadata?.selectedAudioId,
selectionTimestamp: cell.metadata?.selectionTimestamp,
isLocked: cell.metadata?.isLocked,
health: cell.metadata?.health,
},
}));
debug("Translation units:", translationUnits);
Expand Down Expand Up @@ -3414,6 +3456,31 @@ export class CodexCellEditorProvider implements vscode.CustomEditorProvider<Code
throw new Error("Translation cancelled");
}

// Calculate health from example cells for LLM-generated content
// Health = 90% of average example health, but never below baseline (0.3)
let calculatedHealth: number | undefined;
const exampleCellIds = (completionResult as any)?.exampleCellIds;
console.log(`[HealthCalc] Example cell IDs:`, exampleCellIds);
if (exampleCellIds && exampleCellIds.length > 0) {
const indexManager = getSQLiteIndexManager();
if (indexManager) {
const healthMap = await indexManager.getCellsHealth(exampleCellIds);
console.log(`[HealthCalc] Health map size: ${healthMap.size}, values:`, Array.from(healthMap.entries()));
if (healthMap.size > 0) {
const healthValues = Array.from(healthMap.values());
const avgHealth = healthValues.reduce((a, b) => a + b, 0) / healthValues.length;
// Ensure health is at least 0.3 (baseline) - otherwise low-health examples
// would produce even lower health for new cells
calculatedHealth = Math.max(0.3, 0.9 * avgHealth);
console.log(`[HealthCalc] avgHealth: ${avgHealth}, calculatedHealth: ${calculatedHealth}`);
}
} else {
console.log(`[HealthCalc] No index manager available`);
}
} else {
console.log(`[HealthCalc] No example cell IDs provided`);
}

// If multiple variants are present, send to the webview for selection
if (completionResult && Array.isArray((completionResult as any).variants) && (completionResult as any).variants.length > 1) {
const { variants, testId, testName, isAttentionCheck, correctIndex, decoyCellId } = completionResult as any;
Expand All @@ -3430,7 +3497,10 @@ export class CodexCellEditorProvider implements vscode.CustomEditorProvider<Code
currentCellId,
singleCompletion,
EditType.LLM_GENERATION,
shouldUpdateValue
shouldUpdateValue,
false, // retainValidations
false, // skipAutoValidation
calculatedHealth
);
this.updateSingleCellTranslation(1.0);
debug("LLM completion result (identical variants)", { completion: singleCompletion?.slice?.(0, 80) });
Expand Down Expand Up @@ -3489,7 +3559,10 @@ export class CodexCellEditorProvider implements vscode.CustomEditorProvider<Code
currentCellId,
singleCompletion,
EditType.LLM_GENERATION,
shouldUpdateValue
shouldUpdateValue,
false, // retainValidations
false, // skipAutoValidation
calculatedHealth
);

// If this was a preview-only update, persist the edit to disk immediately so edit history is saved
Expand Down
Loading