Project

General

Profile

QA验收 #39 » qa-report.md

Redmine Admin, 11/02/2026 02:24 AM

 

FIN-STAT-PERF 独立QA R1:金额一致性与实际本地接口

记录时间:2026-11-02T10:21:01+08:00(Asia/Shanghai)。正确工单NDB #39;主线程01a18c3a-cafb-7ac0-a552-0ebc24ebc557。

结论

本轮独立 10 Pass / 0 Fail / 0 Blocked / 0 Skipped。19组旧/新真实本地HTTP对照,17组成功响应的字段集合、类型、值及月份顺序全部相同,包含annual_total;另外2组权限拒绝也一致。固定种子300条随机任务加边界夹具,最终333 Task/1126 Cost/9汇率;金额差异0。对象键顺序不作为JSON字段差异,列表月份顺序保留。
未发现本次候选的阻断实现问题。结论限定本批独立合成数据、SQLite及真实本地WSGI/API层;不是生产数据全量一致性证明或生产提速验收。原开发13项及Black/Ruff结果审核适用后复用,未运行其测试命令,不计本轮新执行。

候选与独立对照来源

  • Backend分支bugfix/finance-statistics-performance;HEAD/基线f1aadbdf12ccdaab79fac748baa03ff06d99c380。候选是三文件未提交差异,QA未更改,前后均精确匹配放行SHA。
  • 旧完整views源SHA256:f3e9027ffb1785eb6e5e0ae0b7a2f15b131b10981d78bb268be7d38fc8ee494e;原类及原舍入/毛利函数提取SHA256:43938a31035507448ba72061a04db5ecbbbd21415bd21b559c026e20ae024af0。使用git show f1aadbd:api/finance/views.py及AST精确source segment,并在QA进程编译原FinancialStatistics类,没有改写算法或采用开发test的legacy_monthly_statistics。
  • 保留当前模块仅作为原类所需导入命名空间;旧类明确调用原tasks_income_to_rmb/task_costs_to_rmb,原round_money及calculate_gross_margin_rate也从基线提取执行。services.py、ProjectTasks模型、权限和finance URL文件各自基线/现文件hash相同,因而共享依赖有效不变。证据candidate-and-baseline.json。
候选文件 QA前后SHA256
api/finance/views.py a60309943816d442a47cb40b2fdc68394824df1d29016e9be2320cb005ba3d33
api/finance/statistics.py 9ca03ae35295aa0353d2561e9da58dae0736f18d1c49741c13d12c2dea66d14a
api/finance/test_statistics_performance.py 20fd8f9dff8781a6a0e5b44877c46cfa3687ff9b4e6e32b5d21099d9ca3e578e

本地真实链与安全

先激活crm_backend,复用config.settings.isolated_blacklist_tests:原Env.read_env由该设置显式禁用,不加载仓库.env;仅将SQLite内存库改为本任务qa/qa-synthetic.sqlite3,以供WSGI线程访问。既有模型sync schema,不宣称跑过生产/PostgreSQL迁移。缓存/邮件为本地替代,socket只允许精确127.0.0.1临时HTTP端口、requests外连禁止;记录外连尝试0。
一个本任务WSGI服务使用正常产品URLconf,当前真实URL POST /v1/finances/statistics;仅在QA进程增加/qa-baseline/v1/finances/statistics路由指向原类。两端共用同一数据库、原JWT认证/权限/响应处理,无业务响应mock。3个临时finance/PA/Sales账号均纯合成@example.invalid,通过真实POST /v1/auth/login登录,JWT/随机密码只留内存及临时库,不写证据、不访问BW或真实员工账号。
共38次统计HTTP请求(19对)及3次合成登录;这是10个逻辑场景的支持请求,不另加41条Pass。每对前后财务五类完整行一致;登录和认证会更新本地合成用户审计,不夸称整个库严格零写。

逐项结果

编号/影响 场景与操作预期 实际 状态 证据(本QA目录)
FINQA-01-BOUNDARY / IMP-01 / REG-01 12月多币种/历史汇率与字段优先级:POST年2022至基线及当前真实HTTP;历史、当月、未来、软删汇率与默认回退,company_payment显式0/空/缺失、软删及null删除费用、四分类和小时优先均应保持完整响应一致 {"months": 12, "allResponseFieldsIncludingAnnualTotalEqual": true, "cases": "history/future/deleted/missing rates; four expense categories; company_payment zero/empty/null; deleted/null-deleted/unknown costs; explicit hour priority"} Pass pair-boundary-12-months.json
FINQA-02-FILTERS / IMP-01 / REG-02 客户、年份、状态和专家应付范围:对年2023分别请求公司A/B及字符串0筛选;完成、未完成、跨年、普通零/负收入、合法专家应付零收入按原完整接口比较 {"companyVariants": 3, "yearStatusAndPayableOnly": "same full baseline API; valid zero-income expert payable rows, nonfinished/zero/negative regular income filtered"} Pass pair-filters-1.json; pair-filters-2.json; pair-filters-0.json
FINQA-03-ROUNDING / IMP-01 / REG-01 小数临界、负费用、月年汇总:使用JSON公司支付0.005/0.015/-0.005/-1.005及多类费用;年2031完整API应与旧类逐字段相等,annual_total沿原月度四舍五入汇总 {"allResponseFieldsIncludingAnnualTotalEqual": true, "paymentInfoPrecision": ["0.005", "0.015", "-0.005", "-1.005"], "monthlyThenAnnual": true} Pass pair-rounding.json
FINQA-04-RANDOM / IMP-01 / REG-01/02 固定种子300任务随机差分:seed20261102生成300任务/费用混合状态、币种和公司;对2026全量/公司A/B及2025/2027/2024共6组比较;含闰日和年界,差异应0 {"seed": 20261102, "randomTasks": 300, "queryVariants": 6, "allResponseFieldsEqual": true, "includesLeapAndYearBoundaries": true} Pass random-input.json; pair-random-*.json
FINQA-05-ZERO-INCOME / IMP-01 / REG-01/02 零收入及负费用的毛利边界:年2032仅合法专家应付任务、company_payment=-7.005;完整响应应与旧类相等,收入0时毛利率保持0 {"negativeExpense": "real credit/negative company payment included identically", "annualGrossMargin": 0} Pass pair-zero-income-negative-cost.json
FINQA-06-EMPTY / IMP-01 / REG-02 空年度响应:年2199无任务;七组月数组均12个零,annual_total全部原字段/类型/金额相等 {"twelveMonthsAllFieldsZero": true, "annualTotalEqual": true} Pass pair-empty-year.json
FINQA-07-RATE-EDIT / IMP-01 / REG-01 请求内复用不变成跨请求缓存:仅更新本次合成USD2022-01汇率后再请求;结果须发生对应变化且立即与旧真实接口一致,不手动清缓存 {"nextRequestSeesFixtureRateEdit": true, "matchesRealBaseline": true, "noCacheResetUsed": true} Pass pair-rate-edit-next-request.json
FINQA-08-QUERY-BOUND / IMP-02 / REG-03 实际HTTP统计数据SQL增长:比较小公司1条任务及随机大池中符合目标年/公司的任务子集;实际HTTP中财务数据SELECT保持至多3条,金额仍与旧类一致 {"metrics": {"query-small-old": {"case": "query-small-old", "path": "/qa-baseline/v1/finances/statistics", "dataSQLCount": 18, "allSQLCount": 21, "elapsedSeconds": 0.014752833000000187, "onlyFinancialSelect": true}, "query-small-new": {"case": "query-small-new", "path": "/v1/finances/statistics", "dataSQLCount": 3, "allSQLCount": 6, "elapsedSeconds": 0.006790207999999964, "onlyFinancialSelect": true}, "query-large-old": {"case": "query-large-old", "path": "/qa-baseline/v1/finances/statistics", "dataSQLCount": 170, "allSQLCount": 173, "elapsedSeconds": 0.05354383400000007, "onlyFinancialSelect": true}, "query-large-new": {"case": "query-large-new", "path": "/v1/finances/statistics", "dataSQLCount": 3, "allSQLCount": 6, "elapsedSeconds": 0.00827650000000002, "onlyFinancialSelect": true}}, "notProductionBenchmark": true} Pass sql-observations.json; pair-query-small.json; pair-query-large.json
FINQA-09-PERMISSIONS / IMP-03 / REG-04/05 真实URL、正常登录与权限:独立本地合成finance/pa/sales账号经正常密码登录,不force_authenticate;两端都执行真实JWT认证;finance成功、PA403、匿名401,保留旧Sales允许规则 {"financeAllowed": true, "paDenied": 403, "anonymousDenied": 401, "salesOriginalAllowancePreserved": true, "normalJWTAuthBothViews": true} Pass http-observations.json; pair-permission-pa.json; pair-permission-anonymous.json; pair-permission-sales.json
FINQA-10-READ-ONLY / IMP-03 / REG-04 统计接口财务副作用与隔离:每组旧/新HTTP前后对公司/项目/Task/Cost/汇率完整行比较;统计不得写财务,外连0,业务文件sha始终匹配 {"oldNewHTTPPairs": 19, "financialFullRowsUnchangedEachPair": true, "normalAuthAuditOnlyOutsideFinancialTables": true, "externalAttempts": 0} Pass pair-*.json; cleanup.json; candidate-and-baseline.json

覆盖审查与有效证据复用

唯一影响/回归索引是协调根docs/specs/backend/2026-11-02-finance-statistics-performance.md,由主线程单写,QA未改。下述是该表的证据归属说明,不新增另一套业务矩阵。

  • IMP-01 / REG-01、02:独立原完整接口对照涵盖12月、多币种、历史/未来/删除/缺失汇率,company_payment数值/字符串0与空/缺失回退、费用软删/null-delete/未知分类,显式收费小时优先及客户/年份/状态/应付筛选、细小正负费用、零收入及逐月再年度汇总;300随机任务六变体补独立输入空间。
  • IMP-02 / REG-03:实际HTTP中的统计数据SELECT,小公司1条任务旧18/新3;大随机池符合年度/客户的子集旧170/新3(并非300条全部命中筛选),各完整API金额仍一致。含认证的总SQL旧21/173、新6/6。仅本地SQLite应用参考,不能把本地耗时推成生产SQL计划/时延。开发1/241任务3查询与纯RMB2查询仅复用原层级,不重复跑。
  • IMP-03 / REG-04:仅FinancialStatistics接入新helper、年度汇总留原逻辑;共享services/模型/URL/IsFinanceUser字节不变,其他调用同共享函数的入口保持原实现;源码检索确认views移除的两个旧import无剩余消费者。未执行真实付款/开票/激励等无关写流程。独立权限与财务完整行不变覆盖相邻只读边界,原3项FinancialStatisticsViewTests在开发13项中有效复用。
  • REG-05:已补本地真实HTTP的实际URL、正常密码/JWT登录、年度/客户请求与完整金额;未搭或操作未改Web页面,不宣称真实首页/图表交互通过。上级已明确重点为金额、不强制另搭前端,Web请求体/响应消费者仅源码核对。PostgreSQL执行计划/生产大规模内存/真实并发及生产58秒问题修复效果未测,仍由主线程在后续获准阶段处理。
  • 权限文案提醒:IsFinanceUser原规则允许finance/admin/su/pm/sales,并非所有非finance都拒绝。本批finance200、PA403、匿名401、Sales200与原类一致;索引“非财务403”应限定为无原财务统计许可的角色,不能泛化为Sales/PM也应被拒绝。此为原权限语义澄清,不是本次产品缺陷。
  • 复用审核:原开发13项/Black/Ruff来源见唯一索引“环境与结果”,同基线、同三文件候选/同offline settings;QA前后hash匹配且未改业务源,因此不因换责任线程重跑。QA不是复制这些用例,新增的是旧原类HTTP对照及独立输入/实际正常认证链。

准备错误与保全

一次QA准备错误保留于attempt-01-preparation:费用generator误用amount键,模型拒绝;在WSGI/正式API场景之前退出,0 Pass/0业务Fail。finally已清理仅QA SQLite,业务文件不变。仅修QA字段映射actual_price及离线自检,随后执行尚未开始的正式验收;未重放已有通过结果。support-corrections.md完整说明。
临时WSGI已shutdown/server_close、线程结束;仅本任务SQLite及journal/WAL文件已移除。所有临时账号、角色、fixture随仅QA库删除;不是停用共享专用账号。没有共享服务/测试业务库、生产数据库、真实员工账号或其他任务(包括Issue106)数据接触。候选三文件前后不变、Git status仍仅原三项、diff --check通过。
只写outputs/finance-statistics-performance-20261102/qa;主线程索引未写、产品代码未写,无切分支/worktree/commit/push/PR/部署/生产操作。完整响应比较与SQL/隔离/清理收据分别见comparisons.json、sql-observations.json、http-environment.json、cleanup.json。

Redmine

本次10条结果以一次逻辑批次追加NDB #39并全文读回;不关闭工单或其他issue。回写journal及附件/全文匹配以writeback-receipt.json为准。本地QA通过不代表获准部署,用户“先不要部署”保持有效。

(1-1/11)