search_add Legacy baseline-to-HEAD 對照與修改提案

此文件保留 2026-08-04 master_php74_1 稽核歷史。Current Legacy 已改以 NewStaging 為準;最新差異請看 newstaging_delta_audit_2026-08-05.md

狀態:第 1~7 組與 shared async placeholder 已提交

盤點日期:2026-08-04

最新核對:2026-08-05

基準與範圍

  • API:POST /quote_requests/search_add.json
  • Legacy repo:/Users/mattsu/Documents/Site/get-lancer-docker-2/get-lancer
  • PHP 8 文件指定的 Legacy baseline:ee75b122dcace1aa06a94898c2141392d771be10(2026-04-08)
  • Legacy current:master_php74_1 / cfa660b0c(BAC-3685)
  • PHP 8 current:NewStagingForPHP82_search_add / b587ba7d
  • Legacy 入口:app/Plugin/Quotes/Controller/QuoteRequestsController.php:1808
  • PHP 8 入口:Endpoint/V1/SearchAdd.php:52-117

原本只查 2026-04-04~2026-08-04。這種日期篩選會漏掉「commit 日期較舊、但 baseline 後才合併」的 branch commits,因此正式範圍改為:

ee75b122dcace1aa06a94898c2141392d771be10..cfa660b0c

核對方式:

  1. 檢查上述完整 commit range,不只看 commit 日期或訊息。
  2. 比對 baseline 與 current Legacy 的最終淨差異。
  3. 只追實際進入 search_add 的 controller、matcher、pricing、special flow 與 shared method。
  4. 再與目前 PHP 8 實作、caller 與測試逐項對照。

這個 range 有 3,701 個 commits,其中包含舊日期 branch commits;多組舊 commit 是相同 patch 的重複分支版本,不能重複實作。

結論

預計補 7 組同步行為:

  1. region form response 可直接是 zip code。已完成,commit 8ad6ebc5
  2. travel preference 接受 object、單一字串與字串陣列;三個 flag 全為 0 時,配對資料暫時補 is_provider_travel = 1已完成,commit 837e5163
  3. preserve_to_quote_service_ids 多專家輸入、寫表與配對。已完成,commit 70ada7f9
  4. 未服務指定 category 的 preserve service,套用 quote_service_category_preserve_mutes 規則。已完成,commit 4b3e0af3
  5. auto quote 依 category 設定做 hirereview 排序,並記錄排序方式與前 5 筆 bid。已完成,commit 81771a7c
  6. search_add 精準報價排除 excluded critical option。已完成,commit 5a1cd38b
  7. search_add 的 authorized/direct reserve/direct user 流程不使用 payoff lock;其他既有 PHP 8 caller 維持原行為。

另有 shared async placeholder 差異;reviewer 已同意依 Current Legacy 修改 shared newQuoteRequest consumer payload,精確範圍見下方「Shared async Email placeholder」。

完整 range 稽核摘要

Legacy 變更Current Legacy 最終行為PHP 8 現況結論
d8d5a2e3c BAC-3655region response 可直接是 zip code已接受地址名稱與直接 zip,並補 empty_zip_code log已完成,commit 8ad6ebc5
e67a59dd0 BAC-3658travelpref 支援字串/字串陣列;全 0 時 matcher fallback已保留 JSON array response、補三種格式與 matcher-only fallback已完成,commit 837e5163
cfe284147 + cfa660b0c BAC-3649/3685支援多個 preserve service id;每筆都用自己的 id 判斷 auto pool已解析/寫表/讀表,完整 list 套用 auto、narrow、read-segment 與 bid flag已完成,commit 70ada7f9
da73be57a + 9258a4cf1 BAC-3667/3671未服務 category 時,只有 active mute 才拒絕已在 search_add matcher 補 scoped association/active mute lookup 與 Legacy error log已完成,commit 4b3e0af3
6cc170b94 + c8ae59274 BAC-3634hire/review/both 排序及前 5 筆紀錄已補 Legacy comparator、sort type 與前 5 筆實際 auto bid 紀錄已完成,commit 81771a7c
e8e6408e9 + caf8cf18cBAC-3634 的相同 branch patch已由同一份實作涵蓋不重複實作
98c518ca3 BAC-3592 rollbackexcluded critical option 直接從 pricing format 排除;含 `` 的 option 不再拆前段比對已用 scoped option 排除 critical;其他 shared caller 與 cache 維持原行為
baseline 後 branch merge 的 QuoteBid 淨差異processWantToContactProvider() 沒有 payoff lockPHP 8 會取得 lock,失敗回 code 11search_add caller scoped 對齊
2911ef6f2 BAC-3592 與 Current Legacy 最終淨差異consumer match-complete 的三個 placeholder 為空;provider match 通知仍保留中文標題shared consumer payload 已對齊已完成,commit b587ba7d
11fc75398fbb685462PHP 7.4 signature/字串索引相容不影響 API contract不改

舊日期 branch commits

完整 range 內另出現 2024、2025 日期的 BAC-2917、BAC-2947、BAC-3406 commits。patch-id 核對後,大多是成對的相同 patch,且其最終效果已存在 baseline 或已由目前 PHP 8 parity 實作涵蓋。

因此不依「commit 出現在 range」直接重複搬移,而以 baseline → current Legacy 的淨差異與 current method 為準。

預計修改

1. Region response 直接是 zip code(已完成,commit 8ad6ebc5

Legacy:

  • QuoteRequestsController.php:2526-2576
  • 地址名稱:由 address map 反查 zip code。
  • zip code:若 response 本身是 address map value,直接採用。
  • empty_zip_code log message 會包含 area 判斷與 category id。

PHP 8 實作:

  • location 與觸發條件:Lib/SearchAdd/QuoteRequestCreator.php:101-143
  • active region field 與兩種 response:Lib/SearchAdd/QuoteRequestCreator.php:146-189
  • empty_zip_code log:Lib/SearchAdd/QuoteRequestCreator.php:194-235

已完成:

  • resolveZipCodeFromRegion() 已補直接 zip code 分支,保留 Legacy non-strict membership 語意。
  • 不新增 Legacy 沒有的地區有效性條件。
  • 原始 zip 為空時固定寫 empty_zip_code error log;message 區分 area_namearea_code 與 unresolved。
  • context 保留完整 request payload 並補解析後 location;可能包含敏感 body 欄位,也會與 RouterV3 generic log 重複。本次依 Legacy parity 未自行過濾。
  • 測試:tests/SearchAddStep2IntegrationTest.php:214-294,Core 1 test / 10 assertions、Other 2 tests / 12 assertions、既有明確 zip regression 2 tests / 33 assertions 均通過;明確 zip 不寫 empty_zip_code log。
  • 整支 Step2 測試另有 2 個固定 session 過期造成的既有失敗,與本次 region 調整無關。

2. Travel preference 格式與全 0 fallback(已完成,commit 837e5163

Legacy:

  • QuoteRequestsController.php:2904-2931
  • 支援 object JSON、單一 travel_vendortravel_customerremote 字串及 JSON 字串陣列。
  • CommonHelper.php:342-351:三個 travel flag 合計為 0 時,配對資料暫時補 is_provider_travel = 1,並寫 handleBidLimit error log。

PHP 8 實作:

  • SearchAddInput.php:74-134, 161-163, 545-583:另外保留已 rawurldecode、尚未攤平的 Form 原值;一般 normalized payload 不變。
  • FormSubmissionWriter.php:34-68, 108-124:只有 DB type 為 travelpref 且原值是字串時取原值,讓 JSON string-array 原樣寫入 quote_form_submission_fields.responses;其他 field type 與 PHP array 不改既有規則。
  • RequestSummaryUpdater.php:102-137:支援 object JSON、單一 travel_vendortravel_customerremote 與 JSON 字串陣列;object 的 customer_travel_note 行為保留。
  • AutoQuoteDispatcher.php:39-41, 72-102:三個 flag 都存在且合計為 0 時,只將送入 matcher 的 local array 改成 is_provider_travel = 1;reload 後 response 與 DB 仍維持原值。
  • AutoQuoteDispatcher 的現有 caller 是 search_add 與 quote request copy;Legacy 兩條流程都進同一個 handleNewQuoteRequestAutoQuote(),因此不修改 shared QuoteBid::handleBidLimit()
  • log channel 為 handleBidLimit、level 為 error、context 為空;PDO 各環境保留,Slack 只在 production 開啟,與 Legacy 一致。

SQL / DB:

  • writer:INSERT INTO quote_form_submissions ...INSERT INTO quote_form_submission_fields (... responses, type)
  • updater:UPDATE quote_requests SET is_provider_travel = ?, is_customer_travel = ?, is_remote = ? ... WHERE id = ?
  • matcher fallback 不執行額外 SQL。

測試:

  • SearchAddTravelPreferenceTest.php:11-107:三種格式、全 0 fallback、原 array 不被改、精確 log message、non-zero/missing/invalid negative cases。
  • SearchAddTravelPreferenceIntegrationTest.php:34-98:PHP 8.2 DB transaction 驗證 JSON array 原樣寫入,flags 為 provider 1、customer 0、remote 1,測後 rollback。
  • SearchAddInputTest.php:73-103FormSubmissionWriterTest.php:46-79:raw/normalized 分流及非 travel negative test。
  • Core 合計 5 tests / 20 assertions;Other 合計 4 tests / 8 assertions;travel 專用全部 5 tests / 21 assertions,input / writer 全檔 regression 亦通過。
  • 既有 SearchAddStep4IntegrationTest::testWritesRequestArtifactsForCategory280 仍因固定 session 已失效而在建單前回 error 11;沒有進入本次 writer/updater,與本次差異無關。

3. 多個 preserve service id(已完成,commit 70ada7f9

Legacy:

  • input:QuoteRequestsController.php:1987-2006
  • 寫表:QuoteRequestsController.php:2689-2698
  • matcher 讀表:QuoteService.php:2678-2688
  • BAC-3685 multi auto-pool 修正:QuoteService.php:2758-2810
  • auto/narrow bid 判斷:QuoteService.php:3024-30533142-3174
  • manual matcher 讀表:QuoteService.php:3773-3801
  • table:quote_request_preserve_quote_service_ids

規則:

  • multi input 必須是 array,且每一項都通過 is_numeric();任一項不合法,整組 multi list 清空。
  • 單一 preserve_to_quote_service_id 仍加入 list;去重後每個 id 寫一列。
  • quote_requests.has_preserve 仍只依單一參數,不自行改成由 multi list 判斷。

Legacy 最新規則:

  • cfe284147(BAC-3649)先加入 multi list 與關聯表;當時 auto-pool loop 誤用單筆變數。
  • cfa660b0c(BAC-3685)已將 loop 內四個比較全部改用當前 $p_to_svc_id,並修正 manual matcher 取得 request id 的變數。
  • 每位指定專家都獨立判斷:已在 auto pool 且未 mute 時留在 auto;否則插入 narrow candidate。
  • read-segment exemption、auto/narrow 的 is_preservereasonrequestor_note 都使用完整關聯表清單。
  • quote_requests.has_preservepreserve_quote_service_id 仍只看單筆輸入;只有 multi 時維持 0NULL
  • manual matcher 會用完整清單把服務移到候選前方;但 Legacy 建 manual bid 時 is_preserve 仍只比較單筆變數(QuoteService.php:3989-3991),本次不自行改掉。

PHP 8 實作:

  • SearchAddInput.php:357-386:multi 必須是 array 且全為 numeric;任一 invalid 清空 multi,再合併單筆並依原始值去重。
  • PreserveQuoteServiceWriter.php:12-31SearchAddHandler.php:225-230:request 建立後、配對前逐筆寫關聯表。
  • AutoQuoteMatcher.php:99-185,232-239,373-578:先讀關聯表;表為空才退回單筆,完整清單套用 auto/narrow、read-segment、bid flag、reason/note 與 narrow side effect。
  • AutoQuoteMatcher.php:757-846:初始排序後重新把完整 preserve 清單移到 trim 前方,維持 Legacy「先保留再切前 10 筆」的效果。
  • NewQuoteRequestHandler.php:178-211,1160-1174:manual worker 也按 request id 讀完整 list,逐筆移到候選前方;舊資料才退回 task 單筆參數。
  • NewQuoteRequestHandler.php:368-370:manual bid 的 is_preserve 仍只比較單筆參數,保留 current Legacy 邊界。
  • QuoteRequestCreator 不因 multi 改寫主表單筆欄位。

DB 欄位分類:

table.field來源寫入方式
quote_request_preserve_quote_service_ids.createdLegacy Cake timestamp callbackNOW()
quote_request_preserve_quote_service_ids.quote_request_id新建 quote_requests.idexplicit insert
quote_request_preserve_quote_service_ids.quote_service_id驗證、合併、去重後的 list每個值一列

實測證據更正:

  • Staging 2026-08-04 request 22824 的三筆 narrow preserve bid 是 BAC-3685 上線前 的行為,只能保留為修正前 baseline,不可再當成最新預期。
  • 2026-08-05 PHP 8.2 專用整合測試:兩筆 multi-only 關聯列均建立,兩位指定專家均為 is_auto_quote=1is_narrow_match=0is_preserve=1;invalid multi 整組不寫表且一般 auto bid 的 is_preserve/reason/requestor_noteNULL
  • 最終專用結果:Input 2 tests / 3 assertions;Step 7 Core 2 tests / 30 assertions、Other 1 test / 10 assertions
  • Manual fallback:Step 9 Core 1 test / 12 assertions;兩個已移出一般 category pool 的 multi preserve 專家仍建立 manual bid,且 is_preserve 維持 NULL。既有 manual / related baseline 1 test / 15 assertions 亦通過。

4. Preserve service 未服務 category 的 mute 規則(已完成,commit 4b3e0af3

Legacy:

  • QuoteService.php:6167-6235
  • QuoteServiceCategoryPreserveMute.php:3-24
  • quote_categories_quote_services:照常處理。
  • 未服務該 category:active mute 才拒絕並寫 getPreserveServiceData error log;沒有 active mute 仍允許。

PHP 8:

  • AutoQuoteMatcher.php:487-507:先確認 Legacy base joins 可取得 service,再套 category mute,最後才進 shared referral/資料 lookup;順序與 Legacy 一致。
  • AutoQuoteMatcher.php:570-598:base data 使用 quote_services + users + user_profiles inner joins;再查 quote_categories_quote_services,有關聯直接允許,沒有關聯才查 active mute。
  • QuoteServiceCategoryPreserveMute.php:11-17:精確查 quote_service_id + quote_category_id + is_active=1
  • active mute 時使用 channel getPreserveServiceData,message 與 Legacy 完全相同,該 preserve service 不會被額外插入 auto/narrow 候選。
  • inactive mute 或沒有 mute row 時仍允許;category association 存在時不套用 mute。
  • shared NewQuoteRequestHandler::getPreserveServiceData() 未修改,不影響其其他 caller。

實際 SQL 條件:

SELECT quote_services.id
FROM quote_services
INNER JOIN users ON users.id = quote_services.user_id
INNER JOIN user_profiles ON user_profiles.user_id = users.id
WHERE quote_services.id = ?;
 
SELECT id
FROM quote_categories_quote_services
WHERE quote_service_id = ? AND quote_category_id = ?;
 
SELECT id
FROM quote_service_category_preserve_mutes
WHERE quote_service_id = ? AND quote_category_id = ? AND is_active = 1;

邊界:

  • association 仍是獨立存在性檢查,沒有改成 provider query 的 INNER JOIN
  • mute guard 在 referral guard 前執行;base service/user/profile 不完整時與 Legacy 一樣直接略過且不寫 mute log。
  • guard 只控制 preserve 額外插入/優先處理;若 service 原本已由一般規則進入候選池,不新增 Legacy 沒有的全域排除。
  • 沒有新增 config、DB write、queue、payment、notification 或 response 欄位。

測試:

  • SearchAddStep7IntegrationTest.php:521-598
  • 同一個 core matrix 驗證:未服務+active mute 排除、未服務+inactive mute 允許、有服務關聯+active mute 仍允許。
  • active mute fixture 同時設為 referral,驗證仍先套 mute;同時驗證只寫一筆 getPreserveServiceData log,且 message 完全一致。
  • PHP 8.2:1 test / 6 assertions 通過。

5. Auto quote 排序與前 5 筆紀錄(已完成,commit 81771a7c

Legacy:

  • sort type selector:QuoteRequestAutoQuoteSortType.php:14-23
  • balance 與 category 排序:QuoteService.php:2918-2952
  • 實際 auto bid 前 5 筆:QuoteService.php:2960,2963-3057
  • 寫表:QuoteService.php:3288-3316
  • schema:quote_categories.auto_quote_sort_typequote_request_auto_quote_sort_typesquote_bid_auto_quote_sorts

規則:

  • 先完成 provider 去重與前 10 筆 trim,再依 balance 由高到低,最後才套 category sort。
  • hirequote_services.hired_count 高者優先。
  • review:沒有 feedback 時平均分數預設為 4;兩位都至少 4 分時,比 feedback_count,否則比平均分數。
  • both:request id 為奇數選 hire,偶數選 review;其他值、空值不套 category sort。
  • Legacy comparator 沒有相同值 tie-breaker,值相同仍回 1;本次不可自行補 service id 或 balance 當第二排序。
  • 前 5 筆是在 final gate 通過、即將加入 auto bid dataset 時依序收集;read segment、同 provider、self、ibon tier 等被排除者,以及 narrow bid 都不列入。
  • 只有有效 sort type 且至少一筆 auto bid 時才寫兩張表;authorized mode 不取 sort type,也不寫紀錄。

PHP 8 實作:

  • QuoteRequestAutoQuoteSortType.php:17-44:查 category 設定、解析 both 奇偶,並寫 request 的實際 sort type;既有 reader 46-52 未改語意。
  • QuoteBidAutoQuoteSort.php:21-36:依實際 auto bid 建立順序寫最多 5 筆;既有 reader 43-87 未改語意。
  • AutoQuoteMatcher.php:128-130,187-203:authorized mode 以外,在既有去重/trim/balance sort 後套 category sort。
  • AutoQuoteMatcher.php:257-260,323-326:只收集成功建立的 auto bid id;有效 sort type 且至少一筆 auto bid 時才寫兩張表。
  • AutoQuoteMatcher.php:916-946:保留 Legacy hirereview comparator,包括 zero-feedback 預設 4 與相同值仍回 1
  • shared 範圍仍是 search_add 與 quote request copy,對應 Legacy 共用 handleNewQuoteRequestAutoQuote();未修改既有 response reader。
  • 沒有新增 join/guard、unique/upsert、config、log、queue、payment、notification、response 或 ALB 行為。

驗證:Core 3 tests / 57 assertions;Other 3 tests / 31 assertions。覆蓋 hirereviewboth 兩種奇偶分支、只記前 5 筆、reader shape、未知 type、無 auto bid 與 authorized mode 不寫排序表。

6. Excluded critical pricing option

Legacy current:

  • QuoteFormField.php:424-432
  • input.type != large_imageexclude_pricing = 1 的 option,在 is_show_exclude = false 時直接排除;critical 也沒有例外。
  • QuoteServiceCategory.php:2168-2182 不會把 title|附加輸入 拆成 title 再做 pricing option 比對。

PHP 8 實作:

  • Lib/Model/QuoteFormField.php:534-546:新增 default false$exclude_critical_pricing_options,並使用獨立 _exclude_critical Redis hash field。
  • Lib/Model/QuoteFormField.php:583-591:scoped 模式下 critical 也直接排除;其他 shared caller 預設行為不變。
  • Lib/Model/QuoteServiceCategory.php:2004-2058:原本已沒有 | fallback,未再修改。
  • Lib/SearchAdd/BidPricingResolver.php:185-191,240-246:pricing unit 與 precise pricing 都明確啟用 scoped 模式。
  • search_add 與 copy 共用同一 finalizer,對應 Legacy 兩條流程共用 handleNewQuoteRequestAutoQuote()->handleAutoQuote()
  • 沒有新增 DB write、log、queue、activity、payment、notification、response、config 或 ALB 行為。

驗證:本地 category 159/critical field 2227/excluded option 其他,即使 quote_pricing.critical.3 有價格 999,仍落到 Legacy fallback;Core 2 tests / 30 assertions、Other 4 tests / 50 assertions 全數通過。詳細 caller、cache、input 與測試矩陣見 search_add/details/07_bid_finalize.md

7. search_add 特殊流程的 payoff lock(已完成,commit c3abd3aa

Legacy current:

  • QuoteBid.php:4009-4363
  • processWantToContactProvider() 沒有 acquirePayoffLock()releasePayoffLock(),因此不會因 lock 已被占用而先回 code 11。

PHP 8 實作:

  • Lib/Model/QuoteBid.php:683-708,966-969:增加 use_payoff_lock internal option,預設 true;只有啟用時取得/釋放 lock。
  • search_add callers 明確傳 false
    • AuthorizedContactProcessor.php:42-51
    • DirectReserveProcessor.php:116-129
    • DirectUserProcessor.php:123-135
  • 非 search_add caller 未傳 option,仍使用預設 lock;processCallFee() 的獨立 lock 未修改。
  • 沒有改 DB write、payment、activity、queue、notification、response、config、ALB 或 Legacy DB retry 行為。

驗證:Core 3 tests / 100 assertions;Other 1 test / 9 assertions;完整 shared contact regression 12 tests / 184 assertions;6 個異動檔案 PHP 8.2 syntax 全部通過。

已核對但不列入本次直接修改

Apple code lookup

baseline branch 曾使用 getRowByCode();current Legacy 已回到:

  • QuoteRequestsController.php:2092-2099
  • AppleVerifyLog.php:13-17
  • 只取得 sub,invalid code 安全回 false。

PHP 8 目前直接查 apple_verify_logs,invalid row 會回空 identity,正常 sub lookup 已等效,不需要因本次 branch rollback 新增另一套 model method。

但 PHP 8 會從 Apple/Google identity 補 request email,而 current Legacy 仍以 request 的 User[email] 為主。這是既有 actor-resolution parity 題目,不是本次 baseline 後新增規則;保留在 actor detail 的待重新稽核項目,不混進這次 7 組修改。

Ready coupon rollback

current Legacy 的 QuoteBid::getSiteFee() 已移除 quote_coupon_ready_bids 優先套用。PHP 8 contact fee resolver仍可使用 ready coupon。

search_add 的 authorized/direct reserve/direct user 都是「建立新 bid 後立即 contact」,呼叫前不存在可指向該新 bid 的 ready-coupon row,因此正常 search_add 路徑不可達。本次不修改 shared coupon 行為;測試加 negative assertion,確認 smoke fixture 沒有 ready-coupon side effect。

Shared async Email placeholder

2911ef6f2 觸發了 broader placeholder 稽核,但本 worker 的精確依據是 Current Legacy 最終程式;_sendNewRequestMail() 這三個空字串可追到較早的 85ba3f42f。不得把 2911ef6f2 的其他 placeholder 直接套到整個 shared worker。

Current Legacy:

  • consumer Request_Match_CompleteQuoteService.php:4880-4980,其中 4920-4932ACTION_1_TEXTSTAT_1_TITLESTAT_2_TITLE 為空字串。
  • provider Receive_MatchQuoteService.php:4541-4554 的兩個 STAT_*_TITLE 仍保留中文。

PHP 8:

  • consumer:NewQuoteRequestHandler.php:751-821782,785,787 三個欄位已改成空字串。
  • provider:NewQuoteRequestHandler.php:636-721 已與 Legacy 一致,不修改。

影響所有排入 newQuoteRequest 的 shared caller,包括 search_add booking/second-link、HK copy/edit 與 QuoteRequest fallback。rematchQuoteRequest!$re_match guard 排除,不送 consumer match-complete event。

reviewer 已同意 shared 對齊。只改 MoEngage Complete_Match_Request attributes 的三個值;不改 URL/數值、template、event name、DB write、queue 類型或 config。

程式 commit:b587ba7d。測試:focused payload parity 1 test / 32 assertions、Step 9 Core 2 tests / 44 assertions、Step 9 全部 12 tests / 120 assertions,均通過;容器 PHP 8.2 syntax 通過。

預計修改檔案

程式:

  • Lib/SearchAdd/SearchAddInput.php
  • Lib/SearchAdd/QuoteRequestCreator.php
  • Lib/SearchAdd/RequestSummaryUpdater.php
  • Lib/SearchAdd/AutoQuoteDispatcher.php
  • Lib/SearchAdd/AutoQuoteMatcher.php
  • Lib/SearchAdd/BidPricingResolver.php
  • Lib/SearchAdd/AuthorizedContactProcessor.php
  • Lib/SearchAdd/DirectReserveProcessor.php
  • Lib/SearchAdd/DirectUserProcessor.php
  • Lib/Model/QuoteBid.php
  • Lib/Model/QuoteFormField.php(只在採 optional scoped 參數時修改)
  • Lib/Model/QuoteRequestPreserveQuoteServiceId.php(新增)
  • Lib/Model/QuoteServiceCategoryPreserveMute.php(新增)
  • Lib/Model/QuoteRequestAutoQuoteSortType.php
  • Lib/Model/QuoteBidAutoQuoteSort.php
  • Lib/Util/Task/NewQuoteRequestHandler.php

測試:

  • tests/SearchAddInputTest.php
  • tests/SearchAddStep2IntegrationTest.php
  • tests/SearchAddStep4IntegrationTest.php
  • tests/SearchAddStep5IntegrationTest.php
  • tests/SearchAddStep6IntegrationTest.php
  • tests/SearchAddStep7IntegrationTest.php
  • tests/QuoteBidsWantToContactProviderTest.php
  • tests/SearchAddStep9IntegrationTest.php

第 1~7 組已更新對應 detail doc;第 5 組程式 commit 為 81771a7c,第 6 組為 5a1cd38b,第 7 組為 c3abd3aa。shared async placeholder commit 為 b587ba7d

預計測試

Core:

  1. region response 直接傳 zip code,request location 與 log shape 對齊。已通過
  2. travelpref object/string/string-array;全 0 matcher fallback 不回寫 DB。已通過
  3. multi preserve valid list 寫表、去重、單一 id 合併,且每位可留在 auto pool。已通過
  4. multi preserve 任一 invalid 值時整組丟棄。已通過
  5. 未服務 category:active mute 拒絕;inactive/沒有 mute 允許;已有 category association 時不套 mute。已通過
  6. hirereviewboth 排序與前 5 筆兩張 log table。已通過
  7. excluded critical option 不形成 precise-pricing route。已通過
  8. search_add 三種 contact special flow 不因 payoff lock 回 code 11。已通過
  9. shared Request_Match_Complete 三個 placeholder 為空,URL/數值維持原值。已通過,1 test / 32 assertions

Other regression:

  • 單一 preserve caller 不變。
  • authorized mode 不產生 auto-quote sort log。已通過
  • 沒有 sort type/沒有成功 auto bid 時不寫兩張 sort log table。已通過
  • read-segment preserve exemption 使用完整 id list。
  • invalid/missing multi list 不造成 PHP 8 TypeError。
  • 非 search_add processWantToContactProvider() caller 預設仍使用 payoff lock。已通過
  • ready-coupon row 不在 search_add 新建 bid fixture 中產生或消耗。
  • provider Receive_Match 的兩個中文統計標題保持不變。已通過

DB 與部署

本地 PHP 8.2 DB 已確認存在:

  • quote_request_preserve_quote_service_ids
  • quote_service_category_preserve_mutes
  • quote_request_auto_quote_sort_types
  • quote_bid_auto_quote_sorts

部署前仍需確認 staging/production:

  • 上述四張表 schema 一致。
  • quote_categories.auto_quote_sort_type 已部署。

第 3~7 組與 shared async placeholder 都沒有新增或讀取新的 config key,不需同步 Configuration.php,也不修改 ALB。部署前仍需確認 staging/production 的關聯/mute/排序表 schema 與本地一致;第 6 組另需確認實際 category/field 資料。

請 reviewer 確認

  1. 已同意將上述 7 組 current Legacy 行為拆成原子調整;目前第 1~7 組皆已提交,第 7 組 commit 為 c3abd3aa
  2. multi preserve 已改以 cfa660b0c(BAC-3685)為 current Legacy,不再採用修正前的 narrow-only 結論。
  3. payoff lock 已只對 search_add 三個 caller 停用;其他 PHP 8 caller 維持預設 lock。
  4. 已同意 shared async placeholder 依 Current Legacy 對齊;只清空 consumer Request_Match_Complete 的三個欄位,provider Receive_Match 中文標題保持不變。已提交 b587ba7d