@@ -18,6 +18,10 @@ import type {
1818 ContextEntry ,
1919 ContextEntryKind ,
2020 ContextFetchResult ,
21+ ContextFeedback ,
22+ ContextFeedbackLabel ,
23+ ContextFeedbackStore ,
24+ ContextFeedbackTarget ,
2125 ContextFile ,
2226 ContextFileRole ,
2327 ContextPack ,
@@ -31,6 +35,47 @@ const SOURCE_KINDS = new Set(["local", "remote", "bundled"]);
3135const TRUST_LEVELS = new Set < ContextTrustLevel > ( [ "official" , "maintainer" , "community" , "private" , "untrusted" ] ) ;
3236const ENTRY_KINDS = new Set < ContextEntryKind > ( [ "doc" , "skill" , "reference" , "task-pack" , "repository" ] ) ;
3337const ANNOTATION_KINDS = new Set < ContextAnnotationKind > ( [ "environment" , "version-difference" , "failure-cause" , "convention" , "workaround" ] ) ;
38+ const FEEDBACK_LABELS = new Set < ContextFeedbackLabel > ( [ "useful" , "not-useful" , "outdated" , "inaccurate" , "incomplete" , "wrong-version" , "wrong-example" , "irrelevant" ] ) ;
39+ const FEEDBACK_TARGETS = new Set < ContextFeedbackTarget > ( [ "entry" , "file" , "retrieval-result" , "intervention" ] ) ;
40+
41+ export function validateContextFeedback ( input : unknown , path = "$" ) : ContextValidationResult < ContextFeedback > {
42+ const issues = validateSchemaEnvelope ( input , path ) ;
43+ if ( ! isRecord ( input ) ) return invalidResult ( issues ) ;
44+ requiredString ( input , "feedbackId" , path , issues ) ;
45+ requiredTimestamp ( input , "createdAt" , path , issues ) ;
46+ const target = requiredString ( input , "target" , path , issues ) ;
47+ const label = requiredString ( input , "label" , path , issues ) ;
48+ requiredString ( input , "entryId" , path , issues ) ;
49+ requiredString ( input , "source" , path , issues ) ;
50+ optionalString ( input , "version" , path , issues ) ;
51+ const file = optionalString ( input , "file" , path , issues ) ;
52+ const retrievalId = optionalString ( input , "retrievalId" , path , issues ) ;
53+ const interventionId = optionalString ( input , "interventionId" , path , issues ) ;
54+ if ( target && ! FEEDBACK_TARGETS . has ( target as ContextFeedbackTarget ) ) issues . push ( { path : `${ path } .target` , code : "value" , message : `unsupported feedback target ${ target } ` } ) ;
55+ if ( label && ! FEEDBACK_LABELS . has ( label as ContextFeedbackLabel ) ) issues . push ( { path : `${ path } .label` , code : "value" , message : `unsupported feedback label ${ label } ` } ) ;
56+ if ( file && ! normalizeContextFilePath ( file ) ) issues . push ( { path : `${ path } .file` , code : "path" , message : "must be a normalized relative path" } ) ;
57+ if ( target === "file" && ! file ) issues . push ( { path : `${ path } .file` , code : "required" , message : "file feedback requires file" } ) ;
58+ if ( target === "retrieval-result" && ! retrievalId ) issues . push ( { path : `${ path } .retrievalId` , code : "required" , message : "retrieval feedback requires retrievalId" } ) ;
59+ if ( target === "intervention" && ! interventionId ) issues . push ( { path : `${ path } .interventionId` , code : "required" , message : "intervention feedback requires interventionId" } ) ;
60+ return issues . length ? invalidResult ( issues ) : validResult ( input as unknown as ContextFeedback ) ;
61+ }
62+
63+ export function validateContextFeedbackStore ( input : unknown , path = "$" ) : ContextValidationResult < ContextFeedbackStore > {
64+ const issues = validateSchemaEnvelope ( input , path ) ;
65+ if ( ! isRecord ( input ) ) return invalidResult ( issues ) ;
66+ requiredString ( input , "repository" , path , issues ) ;
67+ if ( ! Array . isArray ( input . feedback ) ) issues . push ( { path : `${ path } .feedback` , code : "type" , message : "expected an array" } ) ;
68+ const ids = new Set < string > ( ) ;
69+ for ( const [ index , item ] of ( Array . isArray ( input . feedback ) ? input . feedback : [ ] ) . entries ( ) ) {
70+ const result = validateContextFeedback ( item , `${ path } .feedback[${ index } ]` ) ;
71+ issues . push ( ...result . issues ) ;
72+ if ( result . value ) {
73+ if ( ids . has ( result . value . feedbackId ) ) issues . push ( { path : `${ path } .feedback[${ index } ].feedbackId` , code : "value" , message : "feedback IDs must be unique" } ) ;
74+ ids . add ( result . value . feedbackId ) ;
75+ }
76+ }
77+ return issues . length ? invalidResult ( issues ) : validResult ( input as unknown as ContextFeedbackStore ) ;
78+ }
3479
3580export function validateContextFile ( input : unknown , path = "$" ) : ContextValidationResult < ContextFile > {
3681 const issues = validateSchemaEnvelope ( input , path ) ;
0 commit comments