Skip to content
This repository was archived by the owner on Jul 29, 2026. It is now read-only.

Fix #49: block false-positive affix bones with canon stem validation - #65

Merged
erinepshovel-code merged 6 commits into
mainfrom
codex/fix-blocking-issues-#30-and-#46-nje8xp
May 16, 2026
Merged

erinepshovel-code merged 6 commits into
mainfrom
codex/fix-blocking-issues-#30-and-#46-nje8xp

Conversation

@erinepshovel-code

Copy link
Copy Markdown
Collaborator

Motivation

  • Prevent false-positive affix emissions when the stripped residual is not a valid stem in the canon, which created spurious affix bones (e.g. unit -> un- + it).
  • Ensure affix emission remains canon-driven and consistent across parser paths by using the existing canon word inventory for residual validation.

Description

  • Build a self._valid_stems set in the backend parser _BoneClassifier from CanonLoader.all_words() and exclude entries with primary == "S" to avoid function-word residuals.
  • In backend/src/edcmbone/parser/turns_rounds.py::classify_sequence, skip emitting prefix/suffix affix bones unless the stripped residual is found in self._valid_stems (applies to both prefix and suffix paths).
  • Add an optional valid_stems parameter to core/operator/matcher.match_affixes and use it to gate prefix/suffix matches so the core matcher can perform equivalent residual validation when desired.
  • Add regression tests under tests/: tests/test_affix_residual_validation.py which asserts negative cases (uncle, unit, universe, under, unique) and positive/canon-dependent cases (e.g., redo, unhappy/linking).

Testing

  • Ran the focused affix regression suite with pytest tests/test_affix_residual_validation.py and fixed a failing assertion by excluding primary == "S" entries from the stem index; final run: 4 passed in 0.04s.
  • Commands executed (session): pytest tests/test_affix_residual_validation.py (initial run showed 1 failure), update applied, then pytest tests/test_affix_residual_validation.py (final run: 4 passed).

Codex Task

Copilot AI review requested due to automatic review settings May 15, 2026 16:59

Copilot AI left a comment

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.

Pull request overview

This PR tightens affix detection by validating stripped residuals against canon stems, while also adjusting apostrophe normalization and test organization.

Changes:

  • Adds canon-backed residual validation for backend parser affix emission and optional stem gating in the core matcher.
  • Normalizes smart apostrophes to ASCII and adds regression tests for contractions and affix false positives.
  • Moves pytest collection toward lowercase tests/ and removes older uppercase/Backend artifacts.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
backend/src/edcmbone/parser/turns_rounds.py Updates tokenizer and affix residual validation in the backend parser.
core/operator/matcher.py Adds optional valid_stems gating to affix matching.
core/parsing/normalizer.py Normalizes smart apostrophe variants to ASCII apostrophes.
tests/test_affix_residual_validation.py Adds regression coverage for affix residual validation.
tests/test_apostrophe_normalization_and_tokenization.py Adds regression coverage for apostrophe normalization/tokenization.
backend/src/edcmbone/ucns/ucns_v04.py Adds packaged UCNS implementation under backend source tree.
backend/src/edcmbone/ucns/closed_tokens.py Updates UCNS import to package-relative form.
backend/pyproject.toml Changes pytest collection path to lowercase tests.
Tests/test_backend.py Removes old uppercase backend regression suite.
Tests/test_closed_tokens.py Removes old uppercase closed-token test copy.
Documentation/spec.md Removes old documentation file.
Backend/requirements.txt Removes old uppercase Backend requirements file.
Backend/LICENSE Removes old uppercase Backend license copy.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


# Split into word-runs and individual punctuation characters
_WORD_RE = re.compile(r"[A-Za-z''\-]+|[^\w\s]|\d+")
_WORD_RE = re.compile(r"[A-Za-z]+(?:'[A-Za-z]+)*|[0-9]+|[^\w\s]")

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

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.

Implemented in commit d0f0119. The backend parser tokenizer now preserves hyphenated compounds as a single surface token by matching [A-Za-z0-9]+(?:-[A-Za-z0-9]+)+ before punctuation, and I added a regression test asserting state-of-the-art stays one token.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Comment thread core/operator/matcher.py Outdated
Comment on lines +80 to +82
residual = root[len(p):]
if valid_stems is not None and residual not in valid_stems:
continue

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

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.

Fixed in commit 9738a77. The match_affixes function now defers validation until after all affixes are stripped, allowing multi-affix words like "redoing" (re+do+ing) to work correctly even when intermediate forms like "doing" are not in valid_stems.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Comment thread core/operator/matcher.py Outdated
Comment on lines +94 to +96
residual = root[:-len(s)]
if valid_stems is not None and residual not in valid_stems:
continue

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

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.

Fixed in commit 9738a77. Both prefix and suffix validation now happen after all affixes are stripped, so words like "redoing" can emit both "re" and "ing" affixes with final root "do" validated against valid_stems.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@copilot apply changes based on this feedback

Comment thread tests/test_apostrophe_normalization_and_tokenization.py Outdated
Comment thread backend/pyproject.toml Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a893814fd9

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".


# Split into word-runs and individual punctuation characters
_WORD_RE = re.compile(r"[A-Za-z''\-]+|[^\w\s]|\d+")
_WORD_RE = re.compile(r"[A-Za-z]+(?:'[A-Za-z]+)*|[0-9]+|[^\w\s]")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve hyphenated compounds in backend tokenizer

Restore hyphen handling in this regex: removing - from the word branch now splits compounds like state-of-the-art into ['state', '-', 'of', '-', 'the', '-', 'art'], so the classifier emits a punctuation bone for each hyphen and inflates K counts. This contradicts the canon rule that hyphenated compounds emit one K per compound word, and it changes structural metrics for any hyphen-rich input.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@codex[agent] apply repair

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

this can be fixed @claude

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Summary

  • I inspected backend/src/edcmbone/parser/turns_rounds.py at the requested path and confirmed the hyphenated-compound tokenizer repair is already present: _WORD_RE matches compound forms like [A-Za-z0-9]+(?:-[A-Za-z0-9]+)+ before punctuation, which preserves tokens like state-of-the-art as a single surface token. backend/src/edcmbone/parser/turns_rounds.pyL207-L208
  • I did not make any additional code changes because the requested repair appears to already be applied in the current branch/worktree (clean git status).

Testing

  • cd /workspace/edcmbone && pytest -q (all tests passing: 21 passed).

View task →

Comment thread tests/test_apostrophe_normalization_and_tokenization.py Outdated
erinepshovel-code and others added 2 commits May 15, 2026 10:05
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@erinepshovel-code

Copy link
Copy Markdown
Collaborator Author

@copilot resolve the merge conflicts in this pull request

Agent-Logs-Url: https://github.com/The-Interdependency/edcmbone/sessions/73154e0c-bf87-4066-b51c-d52b607c3e6f

Co-authored-by: erinepshovel-code <250928284+erinepshovel-code@users.noreply.github.com>
Copilot AI and others added 2 commits May 15, 2026 17:12
…pped

Agent-Logs-Url: https://github.com/The-Interdependency/edcmbone/sessions/13182a36-ab97-4a20-91ff-5e43ffad6f5e

Co-authored-by: erinepshovel-code <250928284+erinepshovel-code@users.noreply.github.com>
Resolved conflicts by keeping our improved implementations:
- Tokenizer with hyphen compound support
- Deferred affix validation in core/operator/matcher.py
- Backend parser with _valid_stems set approach

All tests pass (21 passed).

Co-authored-by: erinepshovel-code <250928284+erinepshovel-code@users.noreply.github.com>

Copilot AI commented May 15, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved in commit 6053b86. Merged origin/main using -X ours strategy to keep our improved implementations (hyphen compound tokenizer, deferred affix validation). All 21 tests pass.

@erinepshovel-code
erinepshovel-code merged commit bb575ad into main May 16, 2026
5 checks passed
@erinepshovel-code
erinepshovel-code deleted the codex/fix-blocking-issues-#30-and-#46-nje8xp branch May 16, 2026 05:18
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants