Identify the protected alias affected by a proposed edit

This commit is contained in:
2026-11-11 12:34:20 +00:00
parent 73ef2c6083
commit 891c204e8f
3 changed files with 49 additions and 6 deletions

View File

@@ -2,7 +2,7 @@
**Updated:** 2026-11-11
**Status:** 8 of nine findings resolved. Findings refer to implementation revision
**Status:** All nine findings resolved. Findings refer to implementation revision
`aa8073c`. See the [implementation plan](implementation.md).
## Review Result
@@ -295,6 +295,8 @@ of identity loss over capitalization and the existing rejection rules.
### R9 — Name the Affected Protected Alias (P3)
**Completed.** Protection feedback identifies a spelling whose occurrence count fell. The alias regression and existing spoken-word protection tests pass.
**Affected plan:** Stage 5, item 4.
**Evidence:** When an identity loses a mention, the
@@ -352,6 +354,6 @@ the unchanged spelling.
- Fresh tests passed for runner, validators, process reporting, LLM adapter,
preflight, response schemas, proposal generation, configuration, and prompts
during the algorithmic audit.
Resolve the findings with focused checks at their owning boundaries. Retain the
current architecture and accepted operator choices.
- After remediation, the fresh full test suite, targeted race checks for the
runner, validators, process reporting, LLM adapter, and CLI, and the CLI build
passed.

View File

@@ -99,8 +99,23 @@ func validateIdentityPreservation(beforeByID, afterByID map[glossary.Identity][]
var selected string
found := false
for identity, beforeItems := range beforeByID {
if len(afterByID[identity]) < len(beforeItems) && len(beforeItems) > 0 {
if spelling := beforeItems[0].canonical; !found || spelling < selected {
afterItems := afterByID[identity]
if len(afterItems) >= len(beforeItems) {
continue
}
// Protect identity counts. Within an identity that lost a mention,
// use spelling counts to identify which alias was affected.
remaining := make(map[string]int)
for _, item := range afterItems {
remaining[item.canonical]++
}
for _, item := range beforeItems {
spelling := item.canonical
if remaining[spelling] > 0 {
remaining[spelling]--
continue
}
if !found || spelling < selected {
selected, found = spelling, true
}
}

View File

@@ -3,6 +3,7 @@ package validators
import (
"reflect"
"sort"
"strings"
"testing"
domain "gitea.maximumdirect.net/eric/audita/v3/internal/core/glossary"
@@ -107,3 +108,28 @@ func TestProtectedNameRepetitionRequiresSurvivingIdentityAndSpokenWordScope(t *t
})
}
}
func TestProtectedNameFindingIdentifiesRemovedAlias(t *testing.T) {
req := Request{
ModuleKey: "glossary",
IndependentEvidence: true,
ReplacementPolicy: proposals.ReplacementPolicyReplaceAll,
WorkingTranscript: &schema.Transcript{Segments: []schema.Segment{
{ID: 1, Text: "Mira spoke to Captain Mira"},
}},
ProtectedTerms: domain.Vocabulary([]domain.Entry{{ID: "mira", Name: "Mira", Aliases: []string{"Captain Mira"}}}, nil),
CandidateProposal: []proposals.EnrichedCorrectionProposal{{
CorrectionProposal: proposals.CorrectionProposal{
TargetSegmentID: 1, OriginalText: "Captain Mira", CorrectedText: "the captain", Confidence: 0.9,
},
}},
}
result, err := ValidateProtectedTerms(req)
if err != nil || len(result.Decisions) != 1 {
t.Fatalf("result=%+v err=%v", result, err)
}
decision := result.Decisions[0]
if decision.Approved || decision.ReasonCode != ReasonProtectedGlossaryTerm || !strings.Contains(decision.Message, `"Captain Mira"`) {
t.Fatalf("finding did not identify the removed alias: %+v", decision)
}
}