Separate glossary context from prompt protection

This commit is contained in:
2026-11-10 20:18:47 +00:00
parent a8eb5aea4d
commit 45e5b381f5
10 changed files with 46 additions and 16 deletions

View File

@@ -2,6 +2,7 @@ package proposal_generation
import (
"context"
"encoding/json"
"fmt"
"strings"
@@ -47,6 +48,16 @@ func ExecuteModuleProposal(ctx context.Context, req ModuleProposalRequest) (cont
return contracts.ProposalResult{}, err
}
protected := make([]string, 0, len(req.ProposalRequest.ProtectedTerms))
for _, term := range req.ProposalRequest.ProtectedTerms {
protected = append(protected, term.Spelling)
}
payload, err := json.Marshal(protected)
if err != nil {
return contracts.ProposalResult{}, fmt.Errorf("marshal protected spellings: %w", err)
}
variables["ProtectedTermsJSON"] = string(payload)
promptMetadata, ok := prompts.LookupMetadata(req.PromptID)
if !ok {
return contracts.ProposalResult{}, fmt.Errorf("unknown prompt ID %q", req.PromptID)

View File

@@ -40,6 +40,7 @@ func TestExecuteModuleProposalBuildsMessagesFromSectionAndDescription(t *testing
Settings: cfg,
WorkingTranscript: transcript,
Glossary: glossary,
ProtectedTerms: []domain.Term{{Spelling: "Separate protection"}},
Section: &section,
},
RunSpec: contracts.ModuleRunSpec{
@@ -76,6 +77,9 @@ func TestExecuteModuleProposalBuildsMessagesFromSectionAndDescription(t *testing
if len(client.calls) != 1 || client.calls[0].PromptID != prompts.PromptIDModuleGrammarProposal || client.calls[0].Context.SectionIndex == nil || *client.calls[0].Context.SectionIndex != 7 {
t.Fatalf("unexpected stage name calls: %+v", client.calls)
}
if got := client.calls[0].Variables["ProtectedTermsJSON"]; got != `["Separate protection"]` {
t.Fatalf("protected spellings = %s", got)
}
if len(out.Proposals) != 1 || out.Proposals[0].CorrectedText != "the" {
t.Fatalf("unexpected proposals: %+v", out)
}

View File

@@ -17,7 +17,7 @@ collections:
- Inappropriate example: correcting "Lyra" to "Jesters" should be omitted because those words are not similar in spoken English, even if "Jesters" appears in the glossary.
- Do not replace one clear glossary term, character name, location, or ordinary word with a different glossary term unless it is a plausible mishearing.
- Preserve correctly identified glossary names and aliases. A recognized glossary term may still be a mishearing of another term; correct that misidentification only when spoken similarity and surrounding context support it.
- Apart from that supported mishearing exception, do not replace, Anglicize, normalize, lowercase, or otherwise alter protected glossary names or aliases away from their glossary spelling.
- Preserve spellings listed under Protected spellings. Glossary context supplies correction targets and guidance.
- Preserve canonical glossary capitalization for protected names and aliases, even if they look unusual.
- If a segment includes categories, treat them as additional transcript context.
- Plural forms of glossary names and aliases are allowed targets when spoken similarity and context support them, even if the plural is not explicitly listed in the glossary.
@@ -28,9 +28,12 @@ collections:
{{ .HardeningPolicy }}
{{ .TranscriptDescriptionBlock }}Glossary:
{{ .TranscriptDescriptionBlock }}Glossary context:
{{ .GlossaryJSON }}
Protected spellings:
{{ .ProtectedTermsJSON }}
Transcript section:
{{ .SectionJSON }}
output:

View File

@@ -18,8 +18,7 @@ collections:
- Apart from the a/an article exception, do not make word substitutions, spelling fixes, homophone fixes, filler cleanup, repetition cleanup, paraphrases, or other semantic rewrites.
- Do not change one written word into a different written word, except for capitalization changes to the same letters and the a/an article exception.
- If a possible correction depends on changing a content word into a different word, omit it here rather than bundling it together with formatting cleanup.
- Treat glossary names and aliases as protected spellings and context.
- Do not replace, Anglicize, normalize, lowercase, or otherwise alter protected glossary names or aliases away from their glossary spelling.
- Do not replace, Anglicize, normalize, lowercase, or otherwise alter spellings listed under Protected spellings away from their glossary spelling.
- Preserve canonical glossary capitalization for protected names and aliases, even if they look unusual.
- If a segment includes categories, treat them as additional transcript context.
- Choose an original_text span that appears exactly once in the current segment text.
@@ -31,9 +30,12 @@ collections:
{{ .HardeningPolicy }}
{{ .TranscriptDescriptionBlock }}Protected glossary/context:
{{ .TranscriptDescriptionBlock }}Glossary context:
{{ .GlossaryJSON }}
Protected spellings:
{{ .ProtectedTermsJSON }}
Transcript section:
{{ .SectionJSON }}
output:

View File

@@ -16,9 +16,8 @@ collections:
- Reject unrelated substitutions like changing "Lyra" to "Jesters".
- Reject antonyms or reversals such as changing "visible" to "invisible".
- Do not add or remove punctuation, alter capitalization only, normalize spacing, remove filler words, collapse repetitions, or make general readability edits.
- Treat glossary names and aliases as protected spellings and context.
- You may correct toward glossary names, aliases, or their plural forms when the correction is acoustically plausible and supported by local context.
- Do not replace, Anglicize, normalize, lowercase, or otherwise alter protected glossary names or aliases that already appear correctly in the transcript.
- Do not replace, Anglicize, normalize, lowercase, or otherwise alter spellings listed under Protected spellings that already appear correctly in the transcript.
- Preserve canonical glossary capitalization for protected names and aliases, even if they look unusual.
- If a segment includes categories, treat them as additional transcript context.
- Choose an original_text span that appears exactly once in the current segment text.
@@ -28,9 +27,12 @@ collections:
{{ .HardeningPolicy }}
{{ .TranscriptDescriptionBlock }}Protected glossary/context:
{{ .TranscriptDescriptionBlock }}Glossary context:
{{ .GlossaryJSON }}
Protected spellings:
{{ .ProtectedTermsJSON }}
Transcript section:
{{ .SectionJSON }}
output:

View File

@@ -20,8 +20,8 @@ collections:
- Do not paraphrase, summarize, reorder ideas, replace content with different wording, or make substantive semantic edits.
- Do not change clear content words just because a different phrasing reads better.
- Do not convert uncertain statements into certain statements.
- Treat glossary names and aliases as protected spellings and context. Accidental repetition of a protected name may be reduced when that identity remains in the segment; preserve substantive references and intentional emphasis.
- Do not replace, Anglicize, normalize, lowercase, or otherwise alter protected glossary names or aliases that already appear correctly in the transcript.
- Accidental repetition of a protected name may be reduced when that identity remains in the segment; preserve substantive references and intentional emphasis.
- Do not replace, Anglicize, normalize, lowercase, or otherwise alter spellings listed under Protected spellings that already appear correctly in the transcript.
- Preserve canonical glossary capitalization for protected names and aliases, even if they look unusual.
- If a segment includes categories, treat them as additional transcript context.
- Choose an original_text span that appears exactly once in the current segment text.
@@ -33,9 +33,12 @@ collections:
{{ .HardeningPolicy }}
{{ .TranscriptDescriptionBlock }}Protected glossary/context:
{{ .TranscriptDescriptionBlock }}Glossary context:
{{ .GlossaryJSON }}
Protected spellings:
{{ .ProtectedTermsJSON }}
Transcript section:
{{ .SectionJSON }}
output:

View File

@@ -93,6 +93,9 @@ func WithSharedVariables(values map[string]string) map[string]string {
result[key] = value
}
}
if _, exists := result["ProtectedTermsJSON"]; !exists {
result["ProtectedTermsJSON"] = "[]"
}
return result
}

View File

@@ -38,9 +38,7 @@ func TestEmbeddedDefinitionsPrepareThroughPromptKit(t *testing.T) {
"SectionJSON": "{\"text\":\"fixture-section\"}",
"PayloadJSON": "[{\"text\":\"fixture-correction\"}]",
}
for key, value := range SharedVariables() {
vars[key] = value
}
vars = WithSharedVariables(vars)
for _, tc := range []struct{ id, instruction, schema, payload string }{
{PromptIDModuleGlossaryProposal, "strongly supported by the glossary", "correction_set.v1.json", "fixture-section"},
{PromptIDModuleHomophonesProposal, "homophone correction assistant", "correction_set.v1.json", "fixture-section"},