Skip to content

test(messages_search): drift-guard + empty-keyword accept-path DSL assertions#396

Open
yujiawei wants to merge 1 commit into
mainfrom
feat/search-empty-filter-drift-guard
Open

test(messages_search): drift-guard + empty-keyword accept-path DSL assertions#396
yujiawei wants to merge 1 commit into
mainfrom
feat/search-empty-filter-drift-guard

Conversation

@yujiawei

Copy link
Copy Markdown
Contributor

What

Two non-blocking test-only follow-ups from the #395 review (empty-keyword search + empty-search guard).

1. Anti-drift guard: hasEffectiveFiltersaddCommonFilters

validate.go::hasEffectiveFilters (the empty-search guard) and dsl.go::addCommonFilters (the query builder) independently hardcode the same SearchFilters field set. Adding a new shared filter (e.g. message_types) to one without the other silently breaks the "empty keyword + new filter" listing path:

  • wired into the builder but not the guard → a legitimate empty-keyword search carrying only the new filter is wrongly rejected 400.
  • wired into the guard but not the builder → the request passes but the DSL emits no clause, degenerating into the full-channel scan the guard exists to prevent.

filter_drift_test.go adds a reflection test that forces every exported SearchFilters field to register an effective sample, plus a per-sample assertion that the guard counts it AND the builder emits an OpenSearch clause for it. A new field with no sample fails immediately with a message pointing at the three places to wire it. Verified load-bearing: temporarily adding a MessageTypes field made the test fail as designed.

2. Accept-path DSL assertions

The existing empty-keyword tests only prove the reject path (no multi_match, blank sender_ids dropped). accept_path_dsl_test.go proves the listing path is alive: empty keyword + real sender_ids / sent_at window / p2p spaceId actually emit the corresponding terms / range / spaceId clauses on both _search and _search_all. A regression that dropped a filter clause would have passed the old suite while silently turning every listing into a full-channel scan.

Test

  • go test ./modules/messages_search/... → PASS
  • go build ./..., go vet ./modules/messages_search/... → clean
  • gofmt clean

Test-only; no production code touched.

Part of #395

…path DSL assertions

Two non-blocking P2 follow-ups from the #395 review:

1. Drift guard between hasEffectiveFilters (validate.go) and addCommonFilters
   (dsl.go). A reflection test forces every exported SearchFilters field to
   register an effective sample; per-sample assertions then prove the validator
   guard and the DSL builder agree on that field. Adding a new shared filter to
   one side without the other now fails CI instead of silently 400-rejecting a
   legitimate empty-keyword listing or degenerating into a full-channel scan.

2. Accept-path DSL assertions for the keyword-optional listing path: empty
   keyword + real sender_ids / sent_at window / p2p spaceId now have explicit
   tests proving the corresponding terms/range/spaceId clauses are emitted, not
   just that the reject path (blank sender_ids, no multi_match) is blocked.

Test-only; no production code touched.

Part of #395
@yujiawei yujiawei requested a review from a team as a code owner June 17, 2026 06:37
@github-actions github-actions Bot added the size/L PR size: L label Jun 17, 2026

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

✅ APPROVE — 模范级的纯测试 PR(+223/-0,无生产代码改动),精准把前几轮反复提的 hasEffectiveFilters/addCommonFilters 口径 drift nit 升级成机械回归护栏。本地实跑全过,无 blocking。

价值:把"靠人记得 lockstep"变成"加字段必红测"

前几轮(#391/#395)大家反复提:hasEffectiveFilters(validator guard)与 addCommonFilters(DSL builder)各自硬编码同一组 filter 字段,加新 filter 漏改一侧会 drift——漏 guard 侧→误拒合法空keyword请求 400;漏 builder 侧→guard 放行但 DSL 无子句→退化全频道扫描(正是 guard 要防的)。本 PR 用测试把这个 drift 变成红测:

  • filter_drift_test.go:effectiveFilterSamples 注册表(每字段一个有效样本)+ 反射 TestSearchFilters_NoUnregisteredFields 强制新增 SearchFilters 字段必须登记,否则红测并提示"3 处 lockstep(guard/builder/本测试)";TestEffectiveFilterSamples_GuardAndBuilderAgree 对每样本双侧断言(guard 认可 + builder 真出 filter 子句),任一侧忘了就红。
  • accept_path_dsl_test.go:补"接受路径"断言——之前只测拒绝路径(空keyword 无 multi_match),这组证空keyword+真filter 时 DSL 真出对应子句(terms on from / range on timestamp / spaceId term),堵住"回归丢了 filter 子句但旧测试仍绿、悄悄变全扫"的盲区。

核实

  • 纯测试,无生产代码改动(2 文件全 _test.go,+223/-0),零回归风险。
  • 7 个测试本地实跑全部 PASS,go vet 干净。
  • 断言期望值正确:时间戳 from:1767196800(2026-01-01)/to:1798732799(2026-12-31末) 与 parseSentAt 实际输出一致(测试跑过自证);blank sender_ids 被 drop 不进 terms;p2p spaceId term 保留(跨 Space 隔离)。
  • drift-guard 覆盖完整:SearchFilters 恰好 3 个导出字段(SenderIDs/SentAtFrom/SentAtTo)与注册表一一对应,反射测试 PASS 自证无遗漏;未来加字段会强制红测。

无 blocking、无 should-fix。这种把"评审中发现的口径一致性隐患"固化成机械护栏的测试,正是防止同类回归的最佳实践。批准。

—— Octo-PR (lml2468)

@Jerry-Xin Jerry-Xin 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.

Test-only PR is in scope for octo-server: it strengthens modules/messages_search coverage around empty-keyword search guards and OpenSearch DSL construction.

💬 Non-blocking

  • 🔵 Suggestion: modules/messages_search/filter_drift_test.go:78 only checks that some "filter" key exists after addCommonFilters. That is enough for current one-field samples, but future samples could accidentally include multiple effective fields and mask a missing clause. Consider asserting field-specific DSL markers per sample if this registry grows.
  • 🔵 Suggestion: modules/messages_search/accept_path_dsl_test.go:129 ignores the json.Marshal error. It is practically unreachable after extractDSL, but handling it would match the helper style used earlier in the file.

✅ Highlights

  • The PR correctly targets the drift risk between hasEffectiveFilters and addCommonFilters.
  • The new _search and _search_all accept-path tests cover the important empty-keyword listing path that existing rejection-focused tests did not.
  • Local verification passed: go test ./modules/messages_search/....

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

[Octo-Q · automated review]

Verdict: Approve — no blocking findings; notes below (data-flow traced).


octo-server PR#396 Review Report

PR: #396
Head SHA: abb84d940068f36f5084608a7e47a6f68bf537db
Title: test(messages_search): drift-guard + empty-keyword accept-path DSL assertions
Reviewer: Octo-Q (automated review)
Scope: Test-only (2 new files, +223/-0, zero production code changes)


1. Verification Summary

Item Status Evidence
effectiveFilterSamples covers all 3 SearchFilters fields validate.go:20-24 — struct has exactly SenderIDs, SentAtFrom, SentAtTo; all 3 registered in filter_drift_test.go:33-37
hasEffectiveFiltersaddCommonFilters parity validate.go:163-178 checks same 3 fields as dsl.go:22-48; drift test asserts both sides per sample
Reflection guard covers future field additions filter_drift_test.go:44-55 iterates reflect.TypeOf(SearchFilters{}).NumField() — any new exported field without a sample fails immediately
Epoch timestamps in range assertions parseSentAt("2026-01-01", true) in Asia/Shanghai → 1767196800; parseSentAt("2026-12-31", false)1798732799 — independently verified via Python datetime
Blank sender ID dropped in terms clause addCommonFilters (dsl.go:26-33) skips s == "" before appending to terms slice
applySpaceIDScope emits spaceId term for p2p dsl.go:80-93channelType == channelTypePerson && spaceID != ""b.Filter(TermQuery("spaceId", spaceID))
applyChannelAndRevoked emits channelId term dsl.go:59-62b.Filter(TermQuery("channelId", normChannelID))
buildSearchAllDSL accept path search_all.go:125-148 — calls addCommonFilters same as _search; type-alias SearchAllReq = SearchMessagesReq (validate.go:76)
No overlap / conflict with existing tests Existing dsl_test.go::TestBuildSearchMessagesDSL_NoKeywordSkipsMultiMatch proves rejection path; new tests prove acceptance path — complementary

2. Findings

No P0/P1 issues found.

P2 — Minor observations (non-blocking)

P2-1: Fragile blank-sender assertion (accept_path_dsl_test.go:56-58)

if strings.Contains(body, `""`) && strings.Contains(body, `"from":["",`) {

The first condition ("") matches any empty string in the entire JSON body. The compound check is sufficient for the current test data (no other empty strings present), but a future refactor adding empty-string metadata could produce a false positive. Consider parsing the JSON and inspecting the from array directly. Severity: nit. Diff-scope: new (this PR).

P2-2: _search_all accept-path test less comprehensive than _search (accept_path_dsl_test.go:122-139)
TestBuildSearchAllDSL_EmptyKeywordRealSenderEmitsTerms only asserts terms + u-real. It does not verify channelId, spaceId, or range clauses for _search_all. The _search side has full clause coverage across 4 tests. Acceptable since addCommonFilters is shared code, but a combined-filters test for _search_all would close the gap. Severity: nit. Diff-scope: new (this PR).

3. Suggestions

  • Consider JSON-parsing the DSL body in assertions rather than strings.Contains for stronger structural guarantees (especially P2-1).
  • A TestBuildSearchAllDSL_AllFiltersEmitAllClauses mirroring the _search combined test would make the _search_all path equally bulletproof.

4. Extra Observations

  • The drift-guard design is well-thought-out: the reflection test catches unregistered fields, and the per-sample guard+builder assertion catches registration without implementation. The failure message pointing at all 3 wire-up locations is excellent DX.
  • The effectiveFilterSamples map is intentionally minimal (one sample per field). The combined-filters test in TestEmptyKeyword_AllFiltersEmitAllClauses covers interaction effects.

5. Data-Flow Trace

Consumed Data Upstream Source Reaches Consumer?
SearchFilters.SenderIDs Test constructs []string{"", "u-real"} ✅ → addCommonFilters drops "", keeps "u-real"terms query on from
SearchFilters.SentAtFrom Test sets "2026-01-01" ✅ → parseSentAt in Asia/Shanghai → epoch 1767196800range.gte on timestamp
SearchFilters.SentAtTo Test sets "2026-12-31" ✅ → parseSentAt + end-of-day → epoch 1798732799range.lte on timestamp
spaceID param Test passes "spaceX" ✅ → applySpaceIDScope for channelTypePersonterm on spaceId
normChannelID param Test passes "G1" / "fake-cid" ✅ → applyChannelAndRevokedterm on channelId
hasEffectiveFilters return Reads SenderIDs, SentAtFrom, SentAtTo from SearchFilters ✅ → drift test asserts true for each sample
Reflection field iteration reflect.TypeOf(SearchFilters{}).NumField() = 3 ✅ → all 3 fields present in effectiveFilterSamples

6. R5 Blind-Spot Checklist

  • C1 (dual-path parity): N/A — test-only PR, no add/remove or create/delete paths touched.
  • C2 (control-flow ordering / nesting): Clear — test helpers (emptyKeywordDSLBody) call production functions once with no nesting or double-application risk. extractDSL is an existing helper reused correctly.
  • C3 (authorization boundary ≠ capability): N/A — no auth/authz code modified.
  • C4 (authorization lifecycle / container-member cascade): N/A — no auth code modified.

7. Cross-Round Blocker Recheck

N/A — first review of this PR.


[Octo-Q] verdict: APPROVE

Test-only PR with well-structured anti-drift guards and accept-path assertions. All test assertions verified against production code data flows. No P0/P1 findings. Two minor nits (P2) noted for optional improvement.

@yujiawei yujiawei left a comment

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.

Code Review — PR #396 (octo-server)

Scope: test-only PR at head abb84d94 — adds filter_drift_test.go (84 LOC) and accept_path_dsl_test.go (139 LOC) under modules/messages_search/. No production code touched (confirmed by diff stat: +223/-0, 2 files).

1. Verification results

Check Result Evidence
go test ./modules/messages_search/... ✅ PASS clean
go test -race ./modules/messages_search/ ✅ PASS no data races
go vet ./modules/messages_search/... ✅ clean
gofmt -l on both new files ✅ clean
go build ./modules/messages_search/... ✅ OK
Drift guard is load-bearing ✅ verified injecting a MessageTypes []string field into SearchFilters makes TestSearchFilters_NoUnregisteredFields fail exactly as designed (with the 3-place wiring message)
Hardcoded epochs CI-portable ✅ verified 1767196800/1798732799 = 2026-01-01/2026-12-31 in Asia/Shanghai; userTimeZone is pinned to Asia/Shanghai with a FixedZone("CST", 8*3600) fallback (util.go:10), so the values do not depend on the CI host's TZ — no flakiness

All PR claims hold up.

2. Assessment

This is a high-quality test-only follow-up to #395. Two complementary mechanisms:

  1. filter_drift_test.go — a reflection-driven invariant tying validate.go::hasEffectiveFilters (the empty-search guard) to dsl.go::addCommonFilters (the query builder). TestSearchFilters_NoUnregisteredFields forces every exported SearchFilters field to register an effectiveFilterSamples entry; TestEffectiveFilterSamples_GuardAndBuilderAgree then proves, per field, that the guard counts it and the builder emits a clause. This closes the real failure modes the description names: a new shared filter wired into only one side either 400-rejects a legitimate empty-keyword listing or silently degenerates into a full-channel scan. The guard provably catches both drift directions (I confirmed: guard-but-not-builder → empty bool → no "filter" key → red; builder-but-not-guard → hasEffectiveFilters=false → red).

  2. accept_path_dsl_test.go — converts the prior "reject-path only" coverage into live accept-path assertions: empty keyword + real sender_ids/sent_at/p2p spaceId actually emit the corresponding terms/range/spaceId clauses on both _search and _search_all. A regression that dropped a filter clause would have passed the old suite while turning every listing into a full-channel scan.

Tests are deterministic, correctly exercise the production code paths, and the assertions match actual olivere/elastic serialization.

3. Non-blocking suggestions (P2 — optional, no merge gate)

These are clarity/robustness nits in the test assertions; none affects correctness, determinism, or the load-bearing property:

  • accept_path_dsl_test.go:53 — the blank-sender-id drop check strings.Contains(body, "") && strings.Contains(body, "\"from\":[\"\",") has a dead first conjunct (Contains(body, "") is always true) and is coupled to slice order: it catches a leading blank id but would silently pass a trailing one (["u-real",""]). For the input the test actually uses (blank-first) it works, and blank-drop is independently covered by validate_test.go. Consider parsing the JSON and asserting the from terms equal exactly ["u-real"].
  • accept_path_dsl_test.go:108 (TestEmptyKeyword_AllFiltersEmitAllClauses) — the bare "from" substring can be satisfied by the range clause's from lower-bound key, not only the terms field. The companion "terms" + "u-real" assertions still uniquely pin the sender clause, so there's no false confidence; tightening to "terms":{"from" would remove the ambiguity.
  • filter_drift_test.go:78 — the builder-side assertion checks for a generic "filter" key rather than the field-specific OS key (from/timestamp). Sound today under the one-field-per-sample invariant; asserting the per-field target key would harden it against a future sample that sets two fields.
  • accept_path_dsl_test.go:83-84 — comment says "spaceId itself plus a sender id keep it a legitimate request," but spaceId is not a SearchFilters field and plays no role in hasEffectiveFilters; only the sender id satisfies the guard. The assertion itself is correct — just the rationale comment over-claims. Worth rewording so a future maintainer doesn't infer that a spaceId-only empty-keyword p2p request would pass validation (it would 400).

4. Coverage notes (blind spots, not defects)

  • The accept-path proof covers _search and _search_all only; _search_files/_search_media/_search_around also call addCommonFilters but have no "filter reaches the builder" assertion. space_filter_test.go pins all four endpoints for spaceId (a separate code path) but not for addCommonFilters reachability. A symmetric table-driven test across the five builders would close this — fine as a fast-follow, not required here.
  • The drift guard binds hasEffectiveFilters ↔ addCommonFilters; a filter that other endpoints need but addCommonFilters omits is outside its stated scope (by design).

Verdict

APPROVED. No P0/P1. All correctness, build, vet, fmt, race, and load-bearing checks pass; the suggestions above are optional polish that do not block merge.

@lml2468 lml2468 added stage:review Review phase - QA/security/code review review:running:qa qa-engineer review in progress review:running:security security-engineer review in progress review:running:code code-reviewer review in progress labels Jun 27, 2026
@lml2468

lml2468 commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

QA Verdict: APPROVE

Scope: Test-only PR (modules/messages_search/{filter_drift_test.go,accept_path_dsl_test.go}, +223 / -0). No production code touched.

Findings

  • Drift-guard is load-bearing & well-designed. TestSearchFilters_NoUnregisteredFields uses reflection over SearchFilters struct fields to force every new shared filter to be registered in effectiveFilterSamples. TestEffectiveFilterSamples_GuardAndBuilderAgree then per-sample asserts that hasEffectiveFilters(sample)==true AND addCommonFilters emits a "filter" clause. This is the exact invariant needed to prevent the validator/builder drift that previously turned an empty-keyword + new-filter request into either a wrongful 400 or a silent full-channel scan. PR body documents a load-bearing dry-run (temporarily adding MessageTypes made the test fail as designed) — credible.
  • Accept-path coverage closes a real gap. The existing suite only proved the rejection path (no multi_match, blank sender_ids dropped). The 5 new tests in accept_path_dsl_test.go prove the listing path is alive on both _search and _search_all: sender_ids → terms on from; sent_at → range on timestamp with both bounds (asserting from:1767196800 and to:1798732799, the exact epoch bounds for 2026-01-01..2026-12-31); p2p + spaceX → spaceId term filter is preserved. Without these, a regression that dropped a filter clause would pass the old suite while silently degrading listings.
  • Failure messages are actionable. Each t.Fatalf/t.Errorf names the missing clause, prints the full DSL JSON, and (for the drift guard) points at the three places a new filter must be wired (validate.go::hasEffectiveFilters, dsl.go::addCommonFilters, the sample registry). Future authors won't need to spelunk.
  • Edge case noticed, not blocking. TestEmptyKeyword_RealSenderIDsEmitsTermsClause checks that the blank sender id is dropped via the heuristic body contains ""AND"from":["",. That check is fine for the current DSL shape but is the only assertion in this file that depends on olivere/elastic`'s array serialisation rather than a positive clause. Worth a brief comment so a future serialiser swap doesn't silently weaken the assertion — non-blocking.

Verify

  • CI Build, Vet, Lint, i18n Lint, Personal MsgSendReq Lint, osv-scan, dependency-review, secret-scan → all SUCCESS on the head commit.
  • CI Test (job Test, run 27670640055) → FAILURE, but every --- FAIL: line is in modules/integration/* (e.g. TestIntegrationTeamGroupExistsIsOwnerScoped, TestOIDCIntegrationE2E_TeamGroup, TestIntegrationCreateTeamGroupEmptyAndDedupMembers) with the root-cause log line Post "http://127.0.0.1:1/channel": dial tcp 127.0.0.1:1: connect: connection refused — the IM channel HTTP dependency is unreachable from the test runner. Not caused by this PR; pre-existing infra-side flake of the integration suite. The PR's own diff lives entirely in modules/messages_search/ and is fully covered by the unit-test job, which passed.
  • PR body reports go test ./modules/messages_search/... → PASS locally, go build ./... clean, go vet ./modules/messages_search/... clean, gofmt clean. Consistent with CI signal for the modules touched.

Verdict: APPROVE. The test design is a real anti-drift hinge, the accept-path assertions close a documented coverage gap, and the only CI red is in an unrelated module due to a missing IM service in the runner.

@lml2468 lml2468 added review:done:qa:approve qa-engineer PASS and removed review:running:qa qa-engineer review in progress labels Jun 27, 2026
@lml2468

lml2468 commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Security Verdict: CLEARED

Scope: Test-only PR. Two new _test.go files in modules/messages_search/. No production code, no dependency, no config, no IaC, no workflow change in the diff.

STRIDE / OWASP sweep

  • Spoofing / AuthN: no authentication code touched. No new credentials, tokens, or identity surfaces. N/A.
  • Tampering / Injection: tests build OpenSearch DSL fixtures and assert serialised shape; no untrusted input reaches a sink. The strings hardcoded (u-real, spaceX, peer, date literals 2026-01-01 / 2026-12-31) are author-controlled fixtures, not propagated to production. N/A.
  • Repudiation / Logging: no log writes added/removed; no audit-path touched. N/A.
  • Information disclosure: assertions print only fixture data on failure (u-real, spaceX, integer epoch bounds). No real PII, no tokens, no credentials, no env-derived secrets — safe to surface in CI logs. ✅
  • Denial of service: drift-guard test enumerates SearchFilters reflect fields (currently 3); accept-path tests build a handful of DSL queries in-process. Bounded, fast, no external I/O, no goroutine fan-out. ✅
  • Elevation of privilege: no role/scope/permission checks touched. N/A.

AuthZ posture (relevant for context): the production guard under test (hasEffectiveFilters) and builder (addCommonFilters) implement the empty-keyword full-channel-scan defence — i.e. a fail-closed boundary against unbounded reads. This PR strictly strengthens that posture by red-test-ing the validator/builder pair against silent divergence (which would otherwise enable a stealth full-scan read path). Net effect on security boundary: positive.

Crypto: no crypto code, no key material, no entropy source touched. N/A.

Dependency / SBOM diff: dependency-review CI check → SUCCESS, osv-scan → SUCCESS, Dependency Review → SUCCESS, Secret Scan (gitleaks) → SUCCESS. The drift test imports github.com/olivere/elastic which is already a transitive dep of modules/messages_search production code — no net SBOM expansion. ✅

CI evidence: secret-scan SUCCESS confirms no leaked tokens/keys committed. Build/Vet/Lint clean. The CI Test red is in modules/integration/* (IM channel HTTP dial refused) — not a security signal, not caused by this PR.

Verdict: CLEARED. Test-only change that hardens an existing read-side boundary; zero new attack surface.

@lml2468 lml2468 added review:done:security:approve security-engineer CLEARED and removed review:running:security security-engineer review in progress labels Jun 27, 2026
@lml2468

lml2468 commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Code Verdict: APPROVE

Scope: 2 new files, 223 added lines, test code only. Same package messages_search (white-box access to unexported helpers).

Design

  • Drift-guard pattern is well-chosen. Two complementary tests — one forces registry completeness via reflect.TypeOf(SearchFilters{}), the other proves guard/builder agreement per registered sample. Splitting them keeps the failure mode unambiguous: missing registry entry vs. one-sided wiring. The 25-line failure message on TestSearchFilters_NoUnregisteredFields reads like documentation — directs the next author to the three call sites that must stay in lockstep. Good investment vs. line-cost.
  • Accept-path tests are the right complement to the existing reject-path tests. Builds the empty-keyword DSL via the real buildSearchMessagesDSL / buildSearchAllDSL paths and JSON-asserts on clause shape. Five tests cover sender_ids (positive + blank-drop), sent_at range (both bounds), p2p spaceId preservation, all-filters-combined, and the parallel _search_all endpoint — coverage matrix is appropriately bounded.

Correctness

  • emptyKeywordDSLBody helper guards against author misuse (if req.Keyword != "" { t.Fatalf("test bug...") }) — nice defensive touch for a helper that only makes sense on the listing path.
  • Epoch bounds asserted as "from":1767196800 (2026-01-01T00:00:00Z) and "to":1798732799 (2026-12-31T23:59:59Z) — both numerically correct.
  • Reflection in TestSearchFilters_NoUnregisteredFields walks only NumField() and reads Name — no panics on private fields, no allocations, no reliance on tags. Robust.
  • Type assertion pattern q.(interface{ Source() (any, error) }) cleanly avoids importing the concrete elastic.Query type at the assertion site while still being type-safe.

Readability / Maintainability

  • File-level comment blocks (accept_path_dsl_test.go header, effectiveFilterSamples doc) explain why the test exists and what regression it catches — pays for itself on the first refactor.
  • Per-test doc comments name the regression class each test pins (e.g. "a regression that dropped a filter clause would have passed the old suite while silently turning every listing into a full-channel scan"). Useful institutional memory.
  • Failure messages always include the DSL body via %s, so failures don't require a rerun-with-prints debugging loop.

Nits (non-blocking)

  1. accept_path_dsl_test.go:53 — the blank-sender-id assertion strings.Contains(body, ""..) / "from":["", relies on the olivere/elastic JSON serialiser ordering. A serialiser swap could weaken (not break) this assertion silently. Worth a one-line comment pinning the expectation, or replace with a positive count assertion (strings.Count(body, "u-real") == 1 && !strings.Contains(body, "from":["",")).
  2. effectiveFilterSamples map literal has 3 entries; consider adding a one-line comment hinting at where to add an entry vs. where the failing test will tell the author (already implied by the long Fatalf, but a // add new SearchFilters fields here marker shortens the path).
  3. Test names use mixed conventions (TestEmptyKeyword_RealSenderIDsEmitsTermsClause vs TestBuildSearchAllDSL_EmptyKeywordRealSenderEmitsTerms vs TestSearchFilters_NoUnregisteredFields). Minor inconsistency, no functional impact.

Verify

  • CI Build / Vet / Lint / i18n / Personal-MsgSendReq Lint / dependency-review / osv-scan / secret-scan → all SUCCESS.
  • CI Test job FAILURE is in modules/integration/* (IM channel HTTP 127.0.0.1:1 connection refused) — pre-existing infra/dependency failure, not caused by or affected by this PR's diff.
  • PR body lists local go test ./modules/messages_search/... PASS plus build/vet/gofmt clean; consistent with CI green on the modules touched.

Verdict: APPROVE. Disciplined, well-documented test additions that turn an implicit invariant (validator/builder field-set parity) into an enforced one and close a real accept-path coverage gap. Nits are stylistic.

@lml2468 lml2468 added review:done:code:approve code-reviewer APPROVED and removed review:running:code code-reviewer review in progress labels Jun 27, 2026
@lml2468

lml2468 commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Aggregate Verdict: APPROVED — 等人工合并

  • qa: APPROVE — drift-guard 是 load-bearing(reflect 强制 SearchFilters 字段注册 + per-sample guard/builder 双向断言),accept-path 5 测覆盖了 sender_ids / sent_at 双 bound / p2p spaceId + _search_all 平行端点。CI Test 红仅在 modules/integration/*(IM channel 127.0.0.1:1 拨号失败),与本 PR 无关。
  • security: CLEARED — test-only diff,无生产代码 / 依赖 / 配置变化。STRIDE/OWASP 全 N/A。dependency-review / osv-scan / secret-scan 全 SUCCESS。净效果:加固了 empty-keyword 全频道扫描这一 fail-closed 读取边界。
  • code: APPROVE — 设计良好(两测分离让失败模式清晰),correctness 已验证(epoch bounds、reflect 安全、type assertion 干净),文档充分。3 条 nits(serializer 依赖注释、registry hint 注释、命名一致性)非阻塞。

下一步: wait-human-merge。绝不自动合并


管理 by pr-tick-octo-server autopilot · tracking: OCTO-497

@lml2468 lml2468 added the review:complete 3 verdicts aggregated, awaiting human merge label Jun 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review:complete 3 verdicts aggregated, awaiting human merge review:done:code:approve code-reviewer APPROVED review:done:qa:approve qa-engineer PASS review:done:security:approve security-engineer CLEARED size/L PR size: L stage:review Review phase - QA/security/code review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants