@@ -367,11 +367,84 @@ func TestRetrieveDocs_ReturnsDocumentContentAndEvidence(t *testing.T) {
367367 if len (got .MatchedTerms ) != 2 {
368368 t .Fatalf ("matched_terms = %#v, want both terms" , got .MatchedTerms )
369369 }
370+ if len (got .MatchedFields ) == 0 {
371+ t .Fatalf ("matched_fields should be populated, got %#v" , got .MatchedFields )
372+ }
370373 if len (got .Matches ) < 2 {
371374 t .Fatalf ("expected evidence matches for both symbols, got %#v" , got .Matches )
372375 }
373376}
374377
378+ func TestRetrieveDocs_ExposesStructuredMatchedFields (t * testing.T ) {
379+ deps := setupTestDeps (t )
380+ tmpDir := t .TempDir ()
381+ docsDir := filepath .Join (tmpDir , "docs" )
382+ deps .RagIndexDir = filepath .Join (tmpDir , ".ccg" )
383+
384+ comm := model.Community {Key : "rules" , Label : "Rules" , Description : "policy rules" }
385+ if err := deps .DB .Create (& comm ).Error ; err != nil {
386+ t .Fatalf ("create community: %v" , err )
387+ }
388+ node := model.Node {QualifiedName : "policy.CheckAccess" , Kind : model .NodeKindFunction , Name : "CheckAccess" , FilePath : "internal/policy/access.go" , StartLine : 1 , EndLine : 20 , Language : "go" }
389+ if err := deps .DB .Create (& node ).Error ; err != nil {
390+ t .Fatalf ("create node: %v" , err )
391+ }
392+ if err := deps .DB .Create (& model.CommunityMembership {CommunityID : comm .ID , NodeID : node .ID }).Error ; err != nil {
393+ t .Fatalf ("create membership: %v" , err )
394+ }
395+ ann := model.Annotation {NodeID : node .ID , Summary : "access policy" }
396+ if err := deps .DB .Create (& ann ).Error ; err != nil {
397+ t .Fatalf ("create annotation: %v" , err )
398+ }
399+ for i , tag := range []model.DocTag {
400+ {AnnotationID : ann .ID , Kind : model .TagDomainRule , Value : "admin approval required" , Ordinal : 0 },
401+ {AnnotationID : ann .ID , Kind : model .TagSideEffect , Value : "admin audit log written" , Ordinal : 1 },
402+ } {
403+ if err := deps .DB .Create (& tag ).Error ; err != nil {
404+ t .Fatalf ("create doc tag %d: %v" , i , err )
405+ }
406+ }
407+
408+ docPath := filepath .Join (docsDir , "internal/policy/access.go.md" )
409+ if err := os .MkdirAll (filepath .Dir (docPath ), 0o755 ); err != nil {
410+ t .Fatal (err )
411+ }
412+ if err := os .WriteFile (docPath , []byte ("# access.go\n \n admin approval and audit docs\n " ), 0o644 ); err != nil {
413+ t .Fatal (err )
414+ }
415+
416+ b := & ragindex.Builder {DB : deps .DB , IndexDir : deps .RagIndexDir , OutDir : docsDir }
417+ if _ , _ , err := b .Build (context .Background ()); err != nil {
418+ t .Fatalf ("Build: %v" , err )
419+ }
420+
421+ result := callTool (t , deps , "retrieve_docs" , map [string ]any {
422+ "query" : "admin" ,
423+ "limit" : float64 (5 ),
424+ "content_limit" : float64 (2000 ),
425+ })
426+ if result .IsError {
427+ t .Fatalf ("retrieve_docs error: %v" , getTextContent (result ))
428+ }
429+
430+ var response retrieveDocsResponse
431+ if err := json .Unmarshal ([]byte (getTextContent (result )), & response ); err != nil {
432+ t .Fatalf ("unmarshal retrieve response: %v" , err )
433+ }
434+ if len (response .Results ) != 1 {
435+ t .Fatalf ("results = %d, want 1: %#v" , len (response .Results ), response .Results )
436+ }
437+ got := map [string ]bool {}
438+ for _ , field := range response .Results [0 ].MatchedFields {
439+ got [field ] = true
440+ }
441+ for _ , want := range []string {"domainRule" , "sideEffect" } {
442+ if ! got [want ] {
443+ t .Fatalf ("matched_fields missing %q: %#v" , want , response .Results [0 ].MatchedFields )
444+ }
445+ }
446+ }
447+
375448func TestRetrieveDocs_ContentLimitZeroOmitsContent (t * testing.T ) {
376449 deps := setupTestDeps (t )
377450 tmpDir := t .TempDir ()
0 commit comments