Skip to content

feat(search): unify word analysis across backends - #1979

Open
PsiACE wants to merge 10 commits into
masterfrom
feat/unified-lexical-analysis
Open

PsiACE wants to merge 10 commits into
masterfrom
feat/unified-lexical-analysis

Conversation

@PsiACE

@PsiACE PsiACE commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

Which issue or RFC does this PR close?

Related to #1969.

Rationale for this change

Apply consistent Chinese word segmentation and query filtering across built-in searchable Families.

What changes are included in this PR?

  • Use Jieba segmentation and bundled English/Chinese stopwords, preserving identifiers, negations and quoted stopwords.
  • Refresh existing lexical projections at startup without changing records, history or vectors.
  • Include stopword attribution, public search and upgrade acceptance tests, and bilingual documentation.

Are there any user-facing changes?

Chinese queries are matched by words. Unquoted stopwords are filtered; negations and quoted stopwords remain searchable.
APIs, v1 formats and ranking defaults remain unchanged.

Stop existing Server and Worker processes before upgrading. Startup refreshes searchable text and may take longer for larger databases.

How was this change tested?

  • uv run --locked prek run -a
  • uv run --locked pytest tests/e2e/test_unified_lexical_search.py tests/e2e/test_lexical_projection_upgrade.py -k sqlite -q
  • make docs-test

AI usage statement

Implemented and validated with OpenAI Codex (GPT-6).

@PsiACE

PsiACE commented Oct 13, 2026

Copy link
Copy Markdown
Member Author

SQLite benchmark: 100,001 DuRetrieval documents; 50 queries for latency, 500 for quality.

Metric master (ee50b36d) master + stopwords only #1969 #1979 (Jieba)
Median latency 3,265 ms 1,802 ms 2,817 ms 33 ms
P95 latency 5,915 ms 4,088 ms 5,405 ms 316 ms
nDCG@10 59.55% 60.97% 61.34% 60.13%
Recall@10 60.25% 61.67% 62.00% 61.46%
Database size 788 MiB 788 MiB 788 MiB 458 MiB
Index build time 17.3 s 17.7 s 17.0 s 30.6 s

Stopwords-only applies #1979’s lists to master’s existing tokens. Full #1979 adds substantial speed and storage savings, with no statistically clear nDCG gain over stopwords-only; it also includes encoding and query-policy changes.

Tradeoffs: ~39 MiB additional installed dependency size, slower indexing, and refreshing existing token projections while retaining the v1 record format.

@PsiACE
PsiACE marked this pull request as ready for review October 13, 2026 16:40
Copilot AI balanced review requested due to automatic review settings October 13, 2026 16:40

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.

🟡 Changes recommended

Several bundled English negations are incorrectly removed from unquoted queries.

1 open finding
What changed in this PR

Unifies lexical analysis across built-in search backends, including Chinese segmentation, stopword handling, and projection upgrades.

Changes:

  • Adds shared Jieba-based tokenization and bundled stopword data.
  • Refreshes lexical projections while preserving records and vectors.
  • Adds cross-backend acceptance tests and bilingual documentation.
File Description
uv.lock Locks Jieba dependency.
tests/​e2e/​test_unified_lexical_search.py Tests unified search behavior.
tests/​e2e/​test_lexical_projection_upgrade.py Tests projection upgrades.
src/​powercontext/​builtin/​runtime/​topic_memory_processing.py Uses shared lexical segmentation.
src/​powercontext/​builtin/​runtime/​composition.py Refreshes projections during startup.
src/​powercontext/​builtin/​runtime/​application.py Bounds queries using lexical words.
src/​powercontext/​builtin/​persistence/​sqlite/​experience_index.py Reconciles SQLite FTS rows.
src/​powercontext/​builtin/​persistence/​lexical_projection.py Implements projection refresh.
src/​powercontext/​builtin/​persistence/​experience_index.py Reuses analyzed projections.
src/​powercontext/​builtin/​artifacts/​topic_memory/​relatedness.py Updates lexical signatures.
src/​powercontext/​builtin/​artifacts/​topic_memory/​fusion.py Aligns snippet query analysis.
src/​powercontext/​builtin/​artifacts/​search.py Implements shared word analysis.
src/​powercontext/​builtin/​artifacts/​lexical_data/​zh.txt Adds Chinese stopwords.
src/​powercontext/​builtin/​artifacts/​lexical_data/​en.txt Adds English stopwords.
pyproject.toml Adds Jieba and license metadata.
LICENSES/​stopwords.txt Records stopword licensing.
e2e/​bub/​uv.lock Updates dependency metadata.
docs/​zh/​docs/​workflows/​search-artifacts.md Documents behavior in Chinese.
docs/​en/​docs/​workflows/​search-artifacts.md Documents behavior in English.
.licenserc.yaml Excludes attributed files from header checks.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/powercontext/builtin/artifacts/search.py
Copilot AI balanced review requested due to automatic review settings October 13, 2026 16:57

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.

🔵 Needs a closer look

Several bundled negative contractions are incorrectly filtered as stopwords, violating the documented negation-preservation behavior.

1 open finding

🧠 Review effort: Balanced

Copilot AI balanced review requested due to automatic review settings October 14, 2026 00:47

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.

🟡 Changes recommended

Topic Memory bounds unfiltered words, allowing stopwords to reject queries or discard meaningful trailing terms.

1 open finding
1 resolved since last review

🧠 Review effort: Balanced

Comment thread src/powercontext/builtin/runtime/application.py Outdated

@hidb4ai hidb4ai 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.

Reviewed 65d40d6822284f9c7ea7c3beca0b2f67314bf012. The query-bound issue remains reproducible (see my reply in the existing thread). One additional processing failure is detailed inline. Please address both before merging.

Comment thread src/powercontext/builtin/artifacts/topic_memory/relatedness.py
Comment thread src/powercontext/builtin/runtime/composition.py
Copilot AI balanced review requested due to automatic review settings October 15, 2026 04:23
@PsiACE

PsiACE commented Oct 15, 2026

Copy link
Copy Markdown
Member Author

ab9aaeda and 65b44047 address these issues: lost quoted or trailing query terms, failures on valid Topic content containing only stopwords, slow SQLite FTS reconciliation, and repeated resegmentation at startup.

On synthetic SQLite fixtures (2 CPUs, 4 GiB):

  • FTS reconciliation with 10,000 unchanged rows: 66.17 s → 0.036 s.
  • Subsequent startup with 100,000 Atomic rows: about 38 s → 0.13 s.

DuRetrieval with 100,001 documents and the first 500 official queries showed unchanged Recall@10 (62.19%) and nDCG@10 (60.80%).

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.

🔵 Needs a closer look

Query parsing regressions remain, and cross-backend startup refreshes need human validation beyond the reported SQLite checks.

0 open findings

1 resolved since last review
Previously missed (2)

In code that hasn't changed since last review

Medium severity Single-quoted contractions lose searchable lexical terms

src/​powercontext/​builtin/​artifacts/​search.py:310

Single-quoted contractions lose the quoted-stopword exemption: lexical_query_words("'I'm'") returns (), while the double-quoted equivalent retains i'm. The quotation regex does not recognize a single-quoted span containing an apostrophe, so this new filter removes the contraction and leaves no FTS evidence. Make the shared quotation parser apostrophe-aware and add a regression for single-quoted contractions.

Medium severity All-directive queries fail to fall back to searchable terms

src/​powercontext/​builtin/​artifacts/​search.py:313

Use only supplied context. Do not call tools. now produces no lexical terms, although each sentence separately remains searchable. The fallback tests the entire query as one directive, so FTS cannot retrieve an identical stored policy. Restore the fallback when all constituent sentences are directives, while continuing to exclude directives accompanying other query evidence.

🧠 Review effort: Balanced

@hidb4ai

hidb4ai commented Oct 15, 2026

Copy link
Copy Markdown
Contributor

please update & resolve conflicts

Copilot AI balanced review requested due to automatic review settings October 15, 2026 15:35

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.

🔵 Needs a closer look

Persistent projection upgrades across three backends require human validation beyond the targeted checks performed here.

1 open finding

🧠 Review effort: Balanced

Comment thread src/powercontext/builtin/artifacts/search.py
Copilot AI balanced review requested due to automatic review settings October 15, 2026 16:05

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.

🔵 Needs a closer look

Search regressions remain unresolved, and cross-backend projection upgrades need native validation and human review.

0 open findings

1 resolved since last review
Previously missed (3)

In code that hasn't changed since last review

Medium severity Preserve please as a query stopword

src/​powercontext/​builtin/​artifacts/​search.py:105

Preserve please as a query stopword. The previous filter included it, but neither bundled list does. As a result, PowerContext Server admits text containing only PowerContext, while please PowerContext Server requires two matches and rejects that same text. Add please to the effective stopwords so a polite prefix does not change admission.

Medium severity Restore fallback for queries with no lexical evidence

src/​powercontext/​builtin/​artifacts/​search.py:319

A query consisting of multiple execution-policy sentences loses all lexical evidence. For example, Do not call tools. Do not read files. returns no words and cannot retrieve an identical stored policy: each sentence is filtered, but the combined string fails _is_execution_sentence, so the fallback never runs. Restore the fallback when filtering leaves no evidence, while still removing stopwords.

Low severity Reset lexical-version markers after restoring an older export

docs/​en/​docs/​operate/​troubleshoot.md:271

Reset the target lexical-version markers after restoring an older export. Step 4 starts the current Server on an empty target, which writes current-version markers. If the source predates this table, omitting its import leaves those markers intact. On restart, refresh_lexical_projections() skips the restored legacy Topic text, so new Chinese query tokens cannot match it. In both locale guides, instruct operators to run DELETE FROM pc_lexical_projection_versions; on the target after restoration and before restarting the Server.

🧠 Review effort: Balanced

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

1.4.0 v1.4.0 release tracking

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants