Release v4.2.6: Critical bugfix for observation validation
Critical Bugfix: - Fixed overly defensive observation validation blocking observations from being saved - Parser now NEVER skips observations - always saves them - Invalid or missing type defaults to "change" (generic catch-all type) - Removed validation requiring title, subtitle, and narrative fields - Prevents critical data loss - partial observations better than no observations Impact: - Before: Missing title, subtitle, OR narrative caused entire observation to be discarded - After: ALL observations preserved regardless of field completeness - Even partial observations contain valuable data: concepts, files_read, files_modified, facts - LLMs make mistakes - system must be resilient and save everything - Consistent with v4.2.5 summary fix Technical changes: - Updated src/sdk/parser.ts:52-67 to never skip observations - Uses "change" as fallback type for invalid/missing types (no schema change) - Updated ParsedObservation interface to allow null for title, subtitle, narrative - Updated SessionStore.storeObservation signature to accept nullable fields - Updated built worker-service.cjs - Bumped version to 4.2.6 in all metadata files 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+22
-22
@@ -7,10 +7,10 @@ import { logger } from '../utils/logger.js';
|
||||
|
||||
export interface ParsedObservation {
|
||||
type: string;
|
||||
title: string;
|
||||
subtitle: string;
|
||||
title: string | null;
|
||||
subtitle: string | null;
|
||||
facts: string[];
|
||||
narrative: string;
|
||||
narrative: string | null;
|
||||
concepts: string[];
|
||||
files_read: string[];
|
||||
files_modified: string[];
|
||||
@@ -49,39 +49,39 @@ export function parseObservations(text: string, correlationId?: string): ParsedO
|
||||
const files_read = extractArrayElements(obsContent, 'files_read', 'file');
|
||||
const files_modified = extractArrayElements(obsContent, 'files_modified', 'file');
|
||||
|
||||
// Validate required fields
|
||||
if (!type || !title || !subtitle || !narrative) {
|
||||
logger.warn('PARSER', 'Observation missing required fields, skipping', {
|
||||
correlationId,
|
||||
hasType: !!type,
|
||||
hasTitle: !!title,
|
||||
hasSubtitle: !!subtitle,
|
||||
hasNarrative: !!narrative
|
||||
});
|
||||
continue;
|
||||
// NOTE FROM THEDOTMACK: ALWAYS save observations - never skip. 10/24/2025
|
||||
// All fields except type are nullable in schema
|
||||
// If type is missing or invalid, use "change" as catch-all fallback
|
||||
|
||||
// Determine final type
|
||||
let finalType = 'change'; // Default catch-all
|
||||
if (type) {
|
||||
const validTypes = ['bugfix', 'feature', 'refactor', 'change', 'discovery', 'decision'];
|
||||
if (validTypes.includes(type.trim())) {
|
||||
finalType = type.trim();
|
||||
} else {
|
||||
logger.warn('PARSER', `Invalid observation type: ${type}, using "change"`, { correlationId });
|
||||
}
|
||||
} else {
|
||||
logger.warn('PARSER', 'Observation missing type field, using "change"', { correlationId });
|
||||
}
|
||||
|
||||
// Validate type
|
||||
const validTypes = ['bugfix', 'feature', 'refactor', 'change', 'discovery', 'decision'];
|
||||
if (!validTypes.includes(type.trim())) {
|
||||
logger.warn('PARSER', `Invalid observation type: ${type}, skipping`, { correlationId });
|
||||
continue;
|
||||
}
|
||||
// All other fields are optional - save whatever we have
|
||||
|
||||
// Filter out type from concepts array (types and concepts are separate dimensions)
|
||||
const cleanedConcepts = concepts.filter(c => c !== type.trim());
|
||||
const cleanedConcepts = concepts.filter(c => c !== finalType);
|
||||
|
||||
if (cleanedConcepts.length !== concepts.length) {
|
||||
logger.warn('PARSER', 'Removed observation type from concepts array', {
|
||||
correlationId,
|
||||
type: type.trim(),
|
||||
type: finalType,
|
||||
originalConcepts: concepts,
|
||||
cleanedConcepts
|
||||
});
|
||||
}
|
||||
|
||||
observations.push({
|
||||
type: type.trim(),
|
||||
type: finalType,
|
||||
title,
|
||||
subtitle,
|
||||
facts,
|
||||
|
||||
Reference in New Issue
Block a user