Skip to content

fix(detection): augment plain source on candidate lifecycle - #267

Open
asteier2026 wants to merge 31 commits into
lipikaramaswamy/feature/detection-semanticsfrom
asteier2026/bugfix/augment-plain-text-drop-seed-entities
Open

asteier2026 wants to merge 31 commits into
lipikaramaswamy/feature/detection-semanticsfrom
asteier2026/bugfix/augment-plain-text-drop-seed-entities

Conversation

@asteier2026

@asteier2026 asteier2026 commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Stacked on #305 (lipikaramaswamy/feature/detection-semantics, current parent 399ede83). Depends on #305; retarget to main after that PR lands.

The augmenter now receives canonical plain source text (COL_TEXT), without engine tags, seed-entity lists, or instructions to avoid existing detections. Both label-mode examples use plain text and retain value, label, context_before, context_after, and reason.

Preserves #305's exact-source grounding, bounded grounding retries, label scope, date policy, independent seed admission, and shared candidate reconciliation. Removes augmentation's obsolete tagged-input dependencies and tag-stripping guidance, including the correction prompt. The old #267 resolve_overlaps() patch is intentionally not ported: duplicate and conflicting discoveries follow #305's existing policy. No every-occurrence instruction or native schema enforcement is added. Public API is unchanged.

Plan and experiment details: plans/267/plain-text-augmentation.md. Tracks #262; separate from the regex work in #265.

Reported replay evidence

These are supplied experiment results from a prompt-only adaptation onto 97c0ae80, not new measurements on this head. Augmentation-only replays retained original validated seeds, sampling, and the 32,768-token output limit; no fresh detector or validator calls were made.

Model Selected known-miss checks: current → plain text Previously correct checks
Luna 6/9 → 9/9 15/15 → 15/15
Nemotron 3.5 Super VL 7/16 → 15/16 9/9 → 9/9
Gemma 4 26B A4B 16/45 → 45/45 6/6 → 3/6

Checks include repeats, not unique-record counts. All 34 Luna/Super attempts returned. Gemma returned 48/51 after failed-attempt recovery on another provider; three still failed output-format validation. Returned replays had no invalid final source spans. The Gemma regression was an organization mention omitted in all three repeats, not a finding discarded by reconciliation.

Average augmentation time including retries rose approximately 19 → 28 seconds for Luna and 19 → 32 seconds for Super. Gemma timing is confounded by concurrent endpoint traffic and provider changes.

This small selected failure-enriched cohort reused saved baselines and is not a fresh counterbalanced comparison. It does not establish population precision/recall, correctness of every additional prediction, or a general quality/performance improvement. A fresh paired provider-backed comparison and investigation of the exact Gemma control remain outstanding; no broad improvement claim is made.

Validation

  • Offline strict/permissive prompt rendering and exact-source example grounding.
  • Sync/async plain-source rendering despite overlapping seeds, plus preservation of literal source markup.
  • Duplicate rediscovery/provenance and conflicting label/bounds behavior through shared reconciliation.
  • Synthetic organization control distinguishing model omission from reconciliation loss; exact reported fixture unavailable locally.
  • 174 focused tests passed; full suite: 1,825 passed with TMPDIR=/tmp and a short pytest base directory to avoid unrelated macOS temporary-path failures.
  • make check passed in an isolated dev/docs environment (the local notebook extras expose existing unused-ignore warnings in refactor(detection): establish deterministic entity candidate lifecycle #305). Strict make docs-build passed.
  • No real PII fixtures, credentials, public API changes, or bundled skill changes.

PR stack

Merge/review order: #305 → #267 → #335.

After a parent is squash-merged, restack the remaining child commits onto the updated parent/main and retarget their PRs as appropriate. These links describe dependency order, not approval or CI status.

@asteier2026
asteier2026 requested a review from a team as a code owner September 14, 2026 16:25
@greptile-apps

greptile-apps Bot commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] This PR appears safe to merge; no new actionable issue was found.

Summary

Augmentation now reads canonical plain source text without detector tags or a seed-entity list.

  • The augmenter finds entities in plain source text, whether or not they were detected already.

The earlier overlap concern is no longer outstanding. asteier2026 accepted the old behavior because augmentation was expected to return minimal spans; the current stack supersedes that behavior with shared longest-first selection.

Reviews (6) · Last reviewed commit: "fix(detection): augment plain source on ..." · Reviewed by Greptile

@asteier2026
asteier2026 force-pushed the asteier2026/bugfix/augment-plain-text-drop-seed-entities branch from cbf4e98 to 36d76a3 Compare September 14, 2026 16:37
Comment on lines +256 to +258
"""
non_augmenter = [item for item in entities if item.source != "augmenter"]
augmenter = [item for item in entities if item.source == "augmenter"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 security Broader sensitive spans discarded

When the augmenter identifies a broader sensitive value that overlaps a narrower detector span, this filter discards the entire augmenter entity instead of preserving its non-overlapping sensitive portion. For example, if the augmenter finds a full street address containing a detector-identified city, only the city reaches validation and replacement. The rest of the address can remain unanonymized.

How this was verified: Only entities retained by resolve_overlaps() are passed into validation and replacement, and no later stage reconstructs the discarded span or its residual intervals.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is by design. If gliner finds Seattle and augment finds "near downtown Seattle", it's better to hold on to the validated gliner entity "Seattle" and throw out the rest. I think it's too messy to try and weed out parts of the augment span that should still be an entity. Augment is supposed to find minimal spans. If "Seattle, Washington" shows up, we want augment to tag "Seattle" and "Washington" individually.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense. Given the augmenter’s minimal-span contract, dropping an overlapping augmenter result is intentional: the validated GLiNER span is preserved, while the augmenter is expected to emit separate minimal entities such as Seattle and Washington rather than a broader span containing Seattle. I’m withdrawing this concern.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updating this older thread to reflect the current stack: #267 has been restacked at 16e9d0d onto #305 head 399ede8. The original seed-overlap rejection patch is no longer part of #267. It changes augmentation input/prompt only; independently grounded/admitted suggestions and detector observations flow through #305's shared eligibility, exact-identity coalescing, and final reconciliation.

Consequently, an eligible broader span is not discarded merely because it overlaps a narrower detector span: greedy longest-first selection prefers the broader supplied span in a containment conflict. Same-bound ties use acceptance/source policy. Partial overlaps still select one supplied span, not a synthetic union or residual intervals; this is not a maximum-total-coverage guarantee. Discriminating containment, later-start/longer, greedy-tradeoff, and excluded-fallback tests live in #305. The restacked #267 passed 1,841 tests, make check, and strict docs build. This supersedes the earlier seed-precedence explanation in this thread.

Copy link
Copy Markdown
Collaborator

@asteier2026 — handoff for bringing this onto #305, including the local experiment results.

What we actually changed locally

We tested a prompt-only adaptation of this PR's a6f683a on the #305 implementation at 97c0ae80. Neither this PR's branch nor its base was changed; #267 still targets main.

The adaptation:

  • Gives the augmenter canonical plain source text (COL_TEXT) instead of the engine-tagged text.
  • Removes the existing/seed-entity list and the instruction not to repeat already-tagged entities.
  • Removes overlap-group/tag-specific instructions and the guidance about stripping engine-inserted tags when copying text.
  • Replaces the tagged example with a plain-text example, while preserving refactor(detection): establish deterministic entity candidate lifecycle #305's value, label, context_before, context_after and reason response fields.
  • Keeps date guidance, label scope, exact-source grounding, grounding retries, admission and final candidate reconciliation unchanged.

We did not apply this PR's overlap-resolver change. #305 replaces that older path with occurrence-specific admitted candidates and shared final reconciliation. That part needs reassessment against #305, rather than carrying the old resolve_overlaps() modification forward unchanged. We also did not add an “every occurrence” instruction or native schema enforcement.

How we tested it

We replayed augmentation only, retaining each original run's exact validated seed candidates. No new detector or validator calls were made. Luna and Nemotron 3.5 Super VL used NVIDIA Inference; Gemma 4 26B A4B used OpenRouter. Sampling and the 32,768-token output limit were unchanged.

Model Selected known-miss target checks protected: current → plain-text adaptation Checks on previously correct examples
Luna 6/9 → 9/9 15/15 → 15/15
Super 7/16 → 15/16 9/9 → 9/9
Gemma 16/45 → 45/45 6/6 → 3/6

A target checked in three repeats contributes three checks; these are not counts of unique records. All 34 Luna/Super replay attempts returned. Gemma returned 48/51 after retrying only failed attempts on another provider; three responses still failed output-format validation. No invalid final source spans were found among returned replays.

The Gemma control regression was an organization mention omitted in all three repeats, not an accepted finding discarded during reconciliation. This needs investigation before claiming the prompt is an across-the-board improvement.

Average augmentation time, including retries, was approximately 19 → 28 seconds for Luna and 19 → 32 seconds for Super. We should not make a causal Gemma speed claim because its replay overlapped other endpoint traffic and failed attempts were recovered on another provider.

Limits: this was a small, selected failure-enriched cohort. We reused saved current-prompt outputs, rather than rerunning both prompts in a fresh counterbalanced comparison. The Gemma recovery also changed providers. These results show recovery of selected missed mentions, not population precision/recall or proof that all additional predictions are correct.

Suggested port

  1. Rebase/retarget onto refactor(detection): establish deterministic entity candidate lifecycle #305 and apply the prompt/input changes to its current augmentation implementation, preserving the context-based response schema and date policy.
  2. Retain refactor(detection): establish deterministic entity candidate lifecycle #305's source grounding, independent seed admission and final reconciliation; reconsider the old overlap patch separately.
  3. Add offline tests for plain-text rendering (including strict/non-strict label modes), duplicate rediscovery, conflicting labels/spans, and source-exact occurrence grounding.
  4. Include the Gemma control omission in a focused follow-up test and run a fresh paired prompt comparison before broad quality/performance claims.

The same results are recorded in the implementation-review comment on #305. This prompt change remains separate from #305 and from the regex work in #265.

@asteier2026
asteier2026 force-pushed the asteier2026/bugfix/augment-plain-text-drop-seed-entities branch from a6f683a to abb6d88 Compare November 3, 2026 16:58
@asteier2026
asteier2026 requested a review from a team as a code owner November 3, 2026 16:58
@asteier2026 asteier2026 changed the title fix: switch augment prompt to plain text input, drop GLiNER seed entities fix(detection): augment plain source on candidate lifecycle Nov 3, 2026
@asteier2026
asteier2026 changed the base branch from main to lipikaramaswamy/feature/detection-semantics November 3, 2026 16:58
@greptile-apps

This comment has been minimized.

@lipikaramaswamy

Copy link
Copy Markdown
Collaborator

Restacked onto the current #305 head, 399ede8. New #267 head: 16e9d0d; base remains lipikaramaswamy/feature/detection-semantics.

Only the original #267 commit was replayed. Range-diff shows the same intended patch (only a surrounding test-helper context changed), so this retains canonical plain-text augmentation, removal of seed/do-not-repeat instructions, and the existing grounding/admission/reconciliation contracts. It also inherits #305 fixes, async-only plugins, test cleanup, documentation, and the bounded grounding optimization. Original author/sign-off preserved; the old tip abb6d88 is retained locally for recovery.

Validation: all 1,841 tests passed; make check and strict make docs-build passed. No provider-backed inference or new quality benchmark was run; the earlier reported experiment remains historical evidence with its existing caveats.

Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
lipikaramaswamy and others added 24 commits November 4, 2026 12:21
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Bind each validator response to an immutable request inventory and use the
same observation-based path for synchronous and asynchronous dispatch.

Keep connected overlap groups together. Treat max_entities_per_call as a
batching target: send an oversized group alone and log only its size and the
configured target.

Tag only observations assigned to the current request. Neighboring detections
remain plain text in its source excerpt, rather than receiving the detector
label tags used by the old excerpt builder. Prompt skeleton offsets index the
untagged excerpt, while the authoritative inventory keeps canonical offsets.

Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Validator drops are no longer re-applied after augmentation. Each decision
governs only its original observation, so an independently admitted augmenter
match of a dropped GLiNER span can now survive finalization, subject to label
eligibility and overlap resolution. This user-visible change can increase
recall or reduce precision; its frequency and benchmark impact are unmeasured.

Track validator-drop rediscovery in the plan and compare main and this branch
on the same dataset, reporting overall precision and recall and the affected
entities' count and precision. Carry this disclosure into the PR description
when the implementation is pushed.

Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Ground augmenter suggestions to exact contextual source occurrences. Preserve successfully grounded items and retry only unsuccessful suggestions once, including their original fields and failure categories without identifiers. Assign observation IDs after combining successful attempts.

Grounding failures no longer fail the whole record: drop remaining ungroundable suggestions while retaining admitted GLiNER candidates and successful augmentation. Record partial outcomes and attempt-local failure indexes and categories without values. Transport and schema failures retain FailedRecord behavior.

Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Publish final entities and tagged text from reconciled occurrence-specific candidates, rather than reinterpreting merged entity values.

Remove:
- Global case-insensitive value propagation via expand_entity_occurrences.
- Automatic splitting of full_name into first, middle, and last name entities.
- Legacy value-only augmentation matching via apply_augmented_entities, its route-local resolve_overlaps policy, and helpers used only by those paths.
- Fallback branches that read legacy entity payloads when required candidate columns are absent.
- Redundant label filtering in merge/finalize and its config and dispatch parameters; admission already enforces label eligibility.
- Unused _seed_tagged_text, _merged_tagged_text, and _validated_seed_entities row columns, including constants and side-effect declarations.

Repeated values and standalone name parts now require occurrence-specific detector or grounded augmenter observations. Missing required candidate columns fail explicitly instead of silently taking a legacy path.

Keep final tagged output, request-specific validator excerpts, and _seed_validation_candidates for measurement. Separate the validator excerpt template variable from stored column constants. Replace obsolete helper tests with candidate-lifecycle, output-contract, and non-propagation coverage.

Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Wrap detector source text in a JSON-encoded object before DataDesigner renders the prompt. Its automatic JSON decoding unwraps the object without reformatting the original source string, keeping detector offsets aligned with canonical text. Drop the temporary wrapper from workflow output.

Cover synchronous and asynchronous prompt generation, formatted JSON objects and arrays, scalar JSON, Unicode, escaping, whitespace, literal Jinja syntax, and canonical-offset parsing with synthetic regression tests.

Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Use 128-word windows with 32-word overlap in the bundled GLiNER2 server and preserve configured window settings in the detection workflow. Reuse the source-safe native-word chunking implementation from main.

Keep overlapping alternatives through native inference and document merging so validation can judge cleaner nested spans. Translate five checkpoint-native inference labels and restore requested labels without narrowing the entity scope or changing the 0.3 threshold.

Include source-offset, window, overlap, and label-mapping tests, deployment guidance, and the targeted benchmark rationale. Augmentation grounding remains unchanged.

Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: lipikaramaswamy <lramaswamy@nvidia.com>
Signed-off-by: asteier2026 <asteier@nvidia.com>
@lipikaramaswamy
lipikaramaswamy force-pushed the asteier2026/bugfix/augment-plain-text-drop-seed-entities branch from 16e9d0d to 1c3e181 Compare November 4, 2026 17:30

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants