204 lines
12 KiB
Markdown
204 lines
12 KiB
Markdown
# Consistent Span Deletion
|
|
|
|
**Last updated:** 2026-09-25
|
|
|
|
**Status:** Implemented. This document owns the desired behavior and user intent.
|
|
The [historical implementation plan](https://gitea.maximumdirect.net/eric/audita/src/commit/60e2fe7/docs/roadmap/implementation.md)
|
|
records the concrete steps, selected implementation details, and completion
|
|
evidence.
|
|
|
|
## Purpose and User Intent
|
|
|
|
Align proposal prompts, the LLM response schema, internal validation, and
|
|
application behavior so legitimate text-span deletions can be considered and
|
|
applied through the ordinary correction workflow. An empty replacement should
|
|
not trigger structural repair merely because it is empty, nor invalidate other
|
|
usable corrections returned alongside it.
|
|
|
|
This is a consistency fix within Audita's current editing scope. It does not
|
|
authorize whole-segment removal, broaden module responsibilities, or introduce
|
|
new recovery machinery. The accepted [resilience behavior](resilience.md) remains
|
|
in effect, including partial success, fixed chunks, and validation before mutation.
|
|
|
|
## Historical Baseline (`0b6cd98`)
|
|
|
|
The source reviewed at `0b6cd98` contains a mismatch:
|
|
|
|
- The [spoken-word prompt](../../internal/prompts/assets/prompts/modules.spoken_word.proposal.yaml)
|
|
permits removing fillers and asks for the exact affected span and replacement,
|
|
without explaining how to represent deletion. Grammar permits punctuation and
|
|
spacing changes, which can also naturally involve deletion.
|
|
- The shared [correction response schema](../../internal/framework/responseschema/assets/correction_set.v1.json)
|
|
requires `corrected_text` to have at least one character. Every built-in proposal
|
|
module uses that schema. An empty replacement invalidates the response before
|
|
Audita evaluates individual proposals.
|
|
- PromptKit performs bounded structural repair. If repair does not produce a
|
|
valid response, the proposal operation fails and yields no candidates, including
|
|
otherwise valid proposals in the same response. The current resilience path
|
|
records the error and continues other work.
|
|
- [CorrectionProposal](../../internal/framework/proposals/proposal.go) already
|
|
allows empty replacement text. The
|
|
[preview/application logic](../../internal/framework/proposals/preview.go)
|
|
supports literal span deletion when the resulting segment remains nonblank.
|
|
- Domain shape checks currently reject whitespace-only original spans, although
|
|
the response schema permits them and grammar prompts permit spacing cleanup.
|
|
This is another restriction to align with the target contract below.
|
|
- The validator named `non_empty_corrected_text` actually checks the resulting
|
|
segment, not the replacement string. Both this check and application prevent
|
|
a segment from becoming empty or whitespace-only. Application changes segment
|
|
text; it does not remove segment records.
|
|
|
|
A temporary controlled-provider review reproduced whole-response rejection for
|
|
an empty replacement alongside a valid correction, and immediate schema acceptance
|
|
for a space-only replacement. Existing proposal tests confirm internal support for
|
|
partial deletion and rejection of blank resulting segments. These observations
|
|
explain a plausible production failure mechanism; they do not establish the cause
|
|
of any particular historical incident without its payload and running version.
|
|
|
|
## Target Correction Contract
|
|
|
|
- `original_text` identifies an existing, nonempty literal span in the current
|
|
target segment. Whitespace-only spans are eligible; an empty string identifies
|
|
no source span and remains invalid. Matching and ambiguity checks still apply
|
|
under the module's replacement policy: `require_unique` for grammar, spoken-word,
|
|
and homophones; `replace_all` for glossary.
|
|
- `corrected_text` remains a required string. An empty string means delete the
|
|
identified span; it does not mean remove the segment record or skip validation.
|
|
Missing fields and non-string values remain structurally invalid.
|
|
- After applying a correction, the segment must contain non-whitespace text.
|
|
Enforce this using the source segment and replacement result in Audita, not a
|
|
minimum replacement length in the structural schema.
|
|
- Every accepted deletion passes the same required validators as other edits in
|
|
its module, including confidence, protected terms, editorial review, and meaning
|
|
preservation where applicable. Empty replacement is neither automatic approval
|
|
nor an automatic rejection.
|
|
- Application preserves segment identity, speaker, timing, membership, ordering,
|
|
and fixed chunk boundaries. Recheck applicability against text produced by
|
|
earlier accepted corrections, retaining existing conflict handling.
|
|
- Preserve literal replacement behavior. Prompts should select spans and
|
|
replacements that handle adjacent whitespace and punctuation appropriately;
|
|
this feature does not add automatic trimming or a second normalization pass.
|
|
Neither side of a correction is rejected solely for containing only whitespace.
|
|
For example, reducing a uniquely identified run of two spaces to one space may
|
|
be appropriate; validity still depends on the resulting text and domain checks.
|
|
|
|
Preserve the intended safeguards and outcomes, not every detail of the current
|
|
implementation. Validator ordering, internal structure, and payload construction
|
|
may change when needed to achieve this consistent contract. Existing behavior or
|
|
a passing test does not justify retaining a conflicting restriction.
|
|
|
|
Illustrative cases:
|
|
|
|
| Segment | Original span | Replacement | Intended handling |
|
|
| --- | --- | --- | --- |
|
|
| `uh hello` | `uh ` | empty string | Structurally valid; may produce `hello` after required validation. |
|
|
| `uh hello` | `uh hello` | `hello` | Remains a valid representation of the same cleanup, subject to validation. |
|
|
| `hello world` | two spaces | one space | Eligible spacing correction, subject to unique matching and required validation. |
|
|
| `uh` | `uh` | empty string | Structurally valid proposal, then filtered because the resulting segment would be blank. |
|
|
| `hello world` | `hello world` | spaces only | Filtered because the resulting segment would be blank. |
|
|
|
|
These examples describe eligibility and mechanical results, not unconditional
|
|
editorial approval. An unchanged segment or valid empty correction list remains
|
|
a successful no-change outcome.
|
|
|
|
## Prompt and Module Alignment
|
|
|
|
Review relevant prompt definitions for consistency and edit only those needing
|
|
clarification. Where needed, explain empty-string deletion, whitespace-only spans,
|
|
and the resulting-segment limit with a concise, module-appropriate example. The
|
|
model should omit a correction that would leave a blank segment rather than invent
|
|
padding or replacement content. Consistent guidance is the goal; adding deletion
|
|
language to every prompt is not a requirement.
|
|
|
|
Retain each module's existing scope:
|
|
|
|
- Spoken-word cleanup can propose appropriate filler or dysfluency deletion while
|
|
preserving substantive content and intentional emphasis.
|
|
- Grammar can propose permitted punctuation or spacing deletion; allowing an
|
|
empty replacement does not authorize word removal or spoken-word cleanup.
|
|
- Glossary and homophone modules retain their existing correction purposes.
|
|
Shared deletion syntax does not grant them new editorial responsibilities.
|
|
|
|
Review the active LLM-validator prompts and their input construction as well as
|
|
proposal prompts. Validators must understand the before/after effect of deletion
|
|
and assess it under their existing criteria. A correct negative editorial decision
|
|
remains ordinary processing, not a defect that should be regenerated until approved.
|
|
|
|
The resulting-segment validator's name and documented identity should describe
|
|
that responsibility accurately, rather than imply that the replacement string
|
|
itself must be nonempty. Preserve the existing blank-result failure reason and
|
|
safeguard while making that deliberate identity change; current chain position
|
|
and preview implementation are not independent product requirements.
|
|
|
|
## Outcomes and Reporting
|
|
|
|
A legitimate deletion is an ordinary correction. Empty replacement alone must
|
|
produce neither structural repair nor a recovery classification. If another
|
|
problem required successful repair or filtering, retain that actual recovery.
|
|
|
|
A schema-valid proposal that would blank its stage-input segment is a defective
|
|
proposal handled through existing safe filtering. Preserve the
|
|
`empty_resulting_segment` reason
|
|
and consolidated `proposals_filtered` recovery behavior; other usable proposals
|
|
in the response continue through required validation. Ordinary editorial rejection
|
|
remains debug evidence rather than a model error or filtering recovery.
|
|
|
|
A stage can propose several edits to one segment in the same response. Each edit
|
|
is evaluated against the stage input, then approved edits are applied sequentially.
|
|
If a proposal was applicable to that input but an earlier accepted edit makes it
|
|
unsafe, skip it as an apply-time conflict. Do not count that conflict as a defective
|
|
proposal, model error, or filtering recovery. For example, in `"uh um"`, deleting
|
|
`"uh "` and deleting `"um"` each leaves text individually; after the first deletion,
|
|
the second must be skipped to prevent a blank result. Retain the skipped decision
|
|
in debug evidence. The existing runner already distinguishes this situation.
|
|
|
|
Debug evidence must accurately retain the empty replacement and the corresponding
|
|
validation/application outcome. Ordinary reports retain their existing counts and
|
|
purpose; no new report schema, incident category, or deletion-specific counter is
|
|
needed. Unrelated structural defects may still exhaust PromptKit repair and produce
|
|
an error for the operation, as today.
|
|
|
|
## Acceptance Criteria
|
|
|
|
- A controlled valid response containing an empty replacement reaches Audita's
|
|
domain validation without structural repair solely due to that empty string.
|
|
- A permitted span deletion can pass the required validators and reach the final
|
|
transcript while preserving segment metadata and fixed chunk membership.
|
|
- A mixed response can apply an approved deletion and another approved correction;
|
|
an empty replacement does not invalidate the whole response.
|
|
- A proposal that would blank its stage-input segment is filtered independently,
|
|
retains the existing reason, and does not prevent unrelated valid candidates
|
|
from succeeding. A proposal made unsafe only by an earlier accepted edit is
|
|
skipped without adding an error or filtering recovery; a blank result is still
|
|
prevented and the conflict remains visible in debug evidence.
|
|
- A uniquely matching whitespace-only original span can reach validation and
|
|
application. Empty originals remain invalid, ambiguous matches remain subject
|
|
to module policy, and whitespace-only resulting segments remain disallowed.
|
|
- Protected-term and meaning-changing deletions remain subject to their normal
|
|
rejection rules. No candidate bypasses required validation.
|
|
- A deletion needing no recovery counts as an ordinary applied correction; actual
|
|
repair/filtering and editorial rejection retain their existing classifications.
|
|
Debug evidence represents the empty replacement faithfully.
|
|
- Schema and domain tests distinguish an empty string from missing/non-string
|
|
replacement values and distinguish empty replacement from blank resulting text.
|
|
- Prompt guidance and validator naming express the same contract as the code.
|
|
Tests protect outcomes rather than exact prompt prose or incidental formatting.
|
|
|
|
Use deterministic, offline controlled responses for behavioral integration tests;
|
|
no live-provider or paid evaluation is a prerequisite. Representative production
|
|
examples can inform prompt quality without expanding this into an evaluation
|
|
framework or guaranteeing that models always follow the instructions.
|
|
|
|
## Deferred Work
|
|
|
|
[Whole-segment removal](future.md#whole-segment-removal) is only potential future
|
|
work and first requires deciding whether its benefit warrants implementation.
|
|
Domain-aware regeneration and independent whole-pipeline traversal also remain
|
|
in [future.md](future.md). This feature changes neither retry budgets nor the
|
|
Audita/PromptKit ownership boundary and requires no upstream library feature.
|
|
|
|
Implementation sequencing and concrete names belong to the
|
|
[historical implementation plan](https://gitea.maximumdirect.net/eric/audita/src/commit/60e2fe7/docs/roadmap/implementation.md).
|
|
The target remains consistent deletion of spans within surviving segments, with
|
|
no new operator controls or report types.
|