• cxk123
    悬赏问答
    ID qa_bounty版本 3.4.1插件制作者 cxk123售价 30 积分3909 行 / 248.5 KBHook / 路由 / 后台页
    3.4.0:**修掉资金路径的三处缺陷**(采纳发放的赏金、入账与账目现在同生共死,中断不再出现「冻结池已扣、答主没拿到、账目没有」的半成品;并发采纳时末位名额取走池中剩余的写回改为带条件写入 + 事务内不变量复核,冻结池不会再被并发击穿、积分不会凭空增发;到期结算的状态推进带上总额校验,与并发加码交错时整条悬赏顺延到下一轮按新总额重算,已结算题上的滞留赏金也纳入对账并按出资比例退回)· 并补上**答主信誉榜的匿名遮蔽**(被遮蔽的回答者此前仍会在页面里留下可反推真实账号的标记,现在彻底不输出)。
    收费插件安装说明购买后点击“授权码”获取一次性授权码;在后台 > 插件广场点击在线安装或更新,并填写该授权码。已购买用户更新免费:每次在线安装或更新前,重新点击“授权码”获取新的一次性授权码即可,无需再次购买;也可直接下载新版后用后台“插件上传”更新。尊重并感谢他人劳动,请勿传播代码。
    app/plugins/qa_bounty/plugin.php
    开发日志最新 10 条

    此项目接受所有登录用户协助维护和提交更新。

    • cxk123
      cxk123
      版本 3.4.1 5f8b4755b98b 更新:**3.4.1 · 悬赏冻结/加码补齐标准积分事件(跨插件契约修复)** - **修复(跨插件契约)**:提问冻结(`qa_bounty_create()`)与加码冻结(`qa_bounty_boost_route()`)用的是自带守卫的原子 CAS 扣款(`points=points-? WHERE ... AND points>=?`),**没有经过核心的积分变动助手** ⇒ 不广播 `userelease
    • cxk123
      cxk123
      版本 3.4.0 e0f10dcd00c7 更新:**3.4.0 · 资金路径三连(采纳发放 / 并发金额 / 到期结算)+ 答主榜匿名遮蔽补齐** - **修复(资金原子性 · 采纳与仲裁)**:采纳答案的三步 —— ①写 `awarded` 扣冻结池(含名额 CAS 与「已解决」置位)、②给答主打积分、③写 `award` 账目 —— 此前是**三次独立提交**。①之后 ②/③ 之前任何失败(进程中断、致命错误、积分入账抛异常)都会留下「**
    • cxk123
      cxk123
      版本 3.3.0 567fe16e362f 更新:**3.3.0 · 榜单与详情的版块可见性** - **修复(越权)**:悬赏榜、悬赏详情、答主信誉榜与「高分榜」组件此前**没有版块可见性判定** ⇒ 「仅指定用户组可见」版块里的悬赏,其**主题标题**会出现在公开榜单、详情与检索结果里。现在五处取数统一按核心同一口径过滤(管理团队作为该版块的合法访问者照常可见;公开版块内容不受影响)。 - **口径**:站内没有受限版块时,SQL 文本**逐
    • cxk123
      cxk123
      版本 3.2.0 d2e5ea4fa640 更新:**3.2.0 · 覆盖升级自愈 + 对账余数** - **修复(覆盖升级会砖)**:本插件此前只会在安装时建表/补列/建索引,而核心在**覆盖文件**时**不重跑安装** ⇒ 老站点覆盖升级后首个查库操作就抛异常(`PDOException`)并**被核心自动停用整个插件**。现在补上运行期结构自愈:**内存副本 → 设置标记 → 才做 DDL** 的三道门,稳态**零查询**,15 个入口全部
    • cxk123
      cxk123
      版本 3.1.0 bb881ac5418c 更新:## 3.1.0:提问者管理台(批量结贴 / 延期 + 诚信分)· 真并发下的三处缺陷修复 ### 新增能力:提问者管理台 `?a=qa_manage` - 一页看完「我的开放悬赏」,带**呆滞标记**:还没有人回答 / 有回答但快到期 / 结贴排队中 / 暂缓结算中 / 到点待结算。 - **批量延期**:勾选若干条一次提交(1–30 天,总期限按 90 天上限自动夹住),催办重新计时。 - *
    • cxk123
      cxk123
      版本 3.0.0 7a28fcc7fe8f 更新:## 3.0.0:全站列表页零查询 · 提问者控制台 · 悬赏订阅(+ 5 处缺陷修复) ### 新增能力 - **列表页 / 首页角标零查询**:悬赏行 → 主题 id 的映射改存 `app_settings` 只读快照,核心在请求开头就把整张设置表读进内存 → 首页 / 版块 / 搜索 / 用户主题等所有列表页渲染「悬赏中 · 已解决」角标**一次库都不用查**(2.0.x 是每个列表页恒定
    • cxk123
      cxk123
      版本 2.0.2 93af58cac73a 更新:## 补丁版本:给「页面组件 DIY」加一个原生组件(未装 layout_diy 时行为逐字节不变) - 新增只读组件注册(私有 Hook `diy_layout.components`):具名渲染回调 + **声明查询成本** + **无数据时零查询降级**(靠站点标记短路)+ 拿不到数据返回空串由宿主降级成占位(**不抛异常**,单块坏天气不会带走整页)。 - 查询形状与行数无关:列表/映射/
    • cxk123
      cxk123
      版本 2.0.1 3549748e933a 更新:**2.0.1 修复:后台设置保存失败时看不到真正的错误原因** * 校验失败时直接 fall through 成整页 HTML,而核心前端对这张表单走 fetch + `JSON.parse` → 用户只看到「操作失败」,真正的提示被吞掉。 * 修法:AJAX 请求回 `{"ok":0,"message":…}` 信封;无 JS 浏览器仍是原来的整页渲染(字节不变)。 * **首次补上 3 张预
    • cxk123
      cxk123
      版本 2.0.0 84c8997a3869 更新:## qa_bounty 2.0.0 —— 先修 BUG,再补能力 本次是大版本更新:**先修掉 6 处真实缺陷 + 1 处窗口竞态**(每一处都在实验室复现过,套件里留了回归断言),再补 5 项新能力。 ### 修掉的缺陷(现象 → 根因 → 修法) 1. **后台「当前冻结总量」与台账互相矛盾**:100 分 / 3 个名额的悬赏采纳 1 条后面板显示冻结 100,账目口径只有 66 —— 冻
    • cxk123
      cxk123
      版本 1.0.0 b6708ca88ef9 更新:悬赏问答 1.0.0 —— 把站内积分变成「悬赏」,让「问得值不值」有答案 【它解决什么问题】 论坛里最贵的资源不是帖子,是**认真回答一个问题的人**。但现在问问题只能靠「有人愿意顺手帮一下」: 问的人没有任何东西可以承诺,答的人也没有任何回报预期,于是「谁懂这个」这类问题要么没人回, 要么被埋在水帖里。悬赏问答补的就是这条链路:**提问时冻结赏金 → 答案被采纳 → 赏金自动转给答主 → 到期
    主楼
  • cxk123

    版本 1.0.0 更新:
    悬赏问答 1.0.0 —— 把站内积分变成「悬赏」,让「问得值不值」有答案

    【它解决什么问题】
    论坛里最贵的资源不是帖子,是认真回答一个问题的人。但现在问问题只能靠「有人愿意顺手帮一下」:
    问的人没有任何东西可以承诺,答的人也没有任何回报预期,于是「谁懂这个」这类问题要么没人回,
    要么被埋在水帖里。悬赏问答补的就是这条链路:**提问时冻结赏金 → 答案被采纳 → 赏金自动转给答主 →
    到期没人被你采纳,积分原路退回**。全程每一笔都有账目,随时可查。

    【新增功能】
    · 挂悬赏提问:发帖页勾选「悬赏」并填写赏金(1 - 10000)、截止天数(1 - 90)、最佳答案数(1 - 3),
    发布时从提问者积分里冻结赏金;余额不足当场拒绝,不会出现「主题发出去了、悬赏却没挂上」的半截结果。
    另有独立的发起页 ?a=qa_ask,不经过发帖页也能直接挂一条悬赏。
    · 采纳与撤销:提问者(或管理团队)在悬赏详情页一键采纳,赏金立即转给答主并通知 TA;
    最佳答案数 > 1 时按「平分、余数归先采纳者」分配。截止前可以撤销采纳(钱收回冻结池,不会重复退款)。
    · 到期自动结算:过了截止时间仍未采纳的部分,由计划任务原路退回提问者并写退回账目、发通知。
    一分未发 → 状态「已退回」;部分采纳 → 状态「已关闭」(已发出的不动)。
    · 悬赏榜与我的悬赏:?a=qa_list 未解决榜按「赏金 × 等待时长」排序(等得越久、赏金越高越靠前),
    另有「已解决 / 我发起的 / 我回答的」三个页签。
    · 主题页联动:挂悬赏的主题在帖子列表里带「悬赏中 · 已解决」角标,主题页顶部显示赏金与剩余时间徽标,
    最佳答案会被顶到当前页最前并标上「最佳答案」。
    · 逐笔账目:冻结(负)/退回(正)/发放(正,撤销时记一笔负),后台面板显示待结算条数与冻结总量,
    两条恒等式随时可对账——「负数合计 = 仍冻结在这条悬赏里的积分」「结算完成后账目合计归零」。

    【跨插件联动(都只经由私有 Hook,对方没装时零影响)】
    · 关注与动态:采纳后把「TA 的回答被采纳、赏金到账」作为一条动态投递给「关注与动态」,
    由对方自行通知答主的关注者——本插件只投递事件,不直接写对方的任何表。
    · 匿名区:悬赏榜与详情页的行在渲染前整页交给匿名区插件批量遮蔽,匿名主题 + 悬赏的组合下,
    列表、详情、甚至连「关注者通知」都不会露出真身(匿名回答被采纳时通知由系统发出)。
    · 全站零打扰:站点上一条悬赏都没有时,列表页角标零额外查询;有悬赏时也只是一次整页批查,
    与行数无关(绝不逐行查库)。

    【性能与安全口径】
    · 页面请求路径上没有任何循环体内的数据库调用;列表页 / 详情页的查询数固定,与条目数无关。
    · 全部写操作 POST + CSRF 令牌;输出统一转义;搜索类查询一律带 ESCAPE 的 LIKE 参数绑定。
    · 冻结是带守卫的 CAS 扣款(UPDATE ... WHERE points>=?),并发下也不会把余额扣成负数;
    发放 / 退回 / 收回一律走核心 user_points_change()。
    · 卸载会清掉自己的 3 张表、索引、计划任务与通知,不留孤儿数据。

    【安装与升级】
    · 单文件插件,装入后启用即用(后台 → 插件 → 本地插件)。自动建 3 张表与 6 枚索引,重复启用幂等。
    · 后台可调:站点开关、赏金上下限、默认截止天数、单题最佳答案数上限、列表每页条数。
    · 计划任务 settle 每 5 分钟结算一次到期悬赏,也可在后台手动触发。

    【兼容】PHP 8.1+ / SQLite / MySQL / PostgreSQL(时间戳全部使用 unix 秒,不使用窗口函数)。

    #1
  • 质量报告

    插件质量报告

    插件:qa_bounty

    Hook功能范围循环使用频率文件读写修改系统表读写系统表读写自己的表
    sidebar.feature_links首页/侧栏快捷功能否5----
    topic.index_data.loaded首页/版块/用户主题列表查询后否5---写 plugin_qa_bounty_questions, plugin_qa_bounty_answers, plugin_qa_bounty_ledger, plugin_qa_bounty_audit, plugin_qa_bounty_watchers, plugin_qa_bounty_watch_events
    topic.title_suffix首页/版块主题列表逐条标题是5----
    topic.replies主题查看页回帖集合否4----
    reply.after_save回帖保存后否3---写 plugin_qa_bounty_questions, plugin_qa_bounty_answers, plugin_qa_bounty_watchers, plugin_qa_bounty_watch_events, plugin_qa_bounty_ledger, plugin_qa_bounty_audit
    topic.actions主题查看页操作区(展示位置:主题操作)否3---写 plugin_qa_bounty_questions, plugin_qa_bounty_answers, plugin_qa_bounty_ledger, plugin_qa_bounty_audit, plugin_qa_bounty_watchers, plugin_qa_bounty_watch_events
    topic.after_save主题保存后否3-app_usersapp_users, app_topics写 plugin_qa_bounty_questions, plugin_qa_bounty_ledger, plugin_qa_bounty_answers, plugin_qa_bounty_audit, plugin_qa_bounty_watchers, plugin_qa_bounty_watch_events
    topic.before_save主题发布/编辑表单提交否3---写 plugin_qa_bounty_questions, plugin_qa_bounty_answers, plugin_qa_bounty_ledger, plugin_qa_bounty_audit, plugin_qa_bounty_watchers, plugin_qa_bounty_watch_events
    topic.form_extra主题发布/编辑表单否2--app_topics写 plugin_qa_bounty_questions, plugin_qa_bounty_answers, plugin_qa_bounty_ledger, plugin_qa_bounty_audit, plugin_qa_bounty_watchers, plugin_qa_bounty_watch_events
    diy_layout.components非系统hook否1----
    reply.content_after非系统hook否1----

    颜色说明:黄色表示有数据读写,红色表示 Hook 在系统循环中执行,浅蓝色表示有文件写入。“列表跳过”表示回调在列表路径会提前返回,“回调内”表示操作位于回调自身或其帮助函数的循环体内。“文件批处理”表示逐个处理用户一次提交的文件,属于必要操作,不标记修正。只有操作实际处于需要优化的循环路径时,才会标记“修正❗️”。

    数据字典

    plugin_qa_bounty_questions

    字段类型可空默认值约束
    -动态定义--无法静态解析

    plugin_qa_bounty_answers

    字段类型可空默认值约束
    -动态定义--无法静态解析

    plugin_qa_bounty_ledger

    字段类型可空默认值约束
    -动态定义--无法静态解析

    plugin_qa_bounty_audit

    字段类型可空默认值约束
    -动态定义--无法静态解析

    plugin_qa_bounty_watchers

    字段类型可空默认值约束
    -动态定义--无法静态解析

    plugin_qa_bounty_watch_events

    字段类型可空默认值约束
    -动态定义--无法静态解析
    #2
  • cxk123

    版本 2.0.0 更新:

    qa_bounty 2.0.0 —— 先修 BUG,再补能力

    本次是大版本更新:先修掉 6 处真实缺陷 + 1 处窗口竞态(每一处都在实验室复现过,套件里留了回归断言),再补 5 项新能力。

    修掉的缺陷(现象 → 根因 → 修法)

    1. 后台「当前冻结总量」与台账互相矛盾:100 分 / 3 个名额的悬赏采纳 1 条后面板显示冻结 100,账目口径只有 66 —— 冻结总量按 SUM(status=0 的 reward) 求和,部分采纳时把已发放的赏金也算成冻结。改为由逐笔账目推出,并新增一行「对账」把两个口径摆在一起。
    2. 撤销采纳后重新采纳会把余数永久留在冻结池:100 分 / 3 个名额绕一圈只发出 99,题目已是「已解决」而账目合计是 −1。末位名额改为取走池子里剩下的全部(正常路径分毫不变)。
    3. 同一条答案被并发采纳两次会重复发放(实测 100 分悬赏给同一条答案发了 68):答案行的 CAS 结果没人看。改为以答案行 CAS 为闸门,抢不到就回滚名额并报错;分配序号改用 CAS 之后的新值。
    4. 热帖(200+ 答案)打开悬赏详情页会撞 UNIQUE(question_id,reply_id),核心记 PDOException 并停用整个插件(页面全 404):补登记的「已登记集合」只从详情页 LIMIT 200 的展示窗口里取。改为单独查全量已登记回帖;并发撞唯一约束按幂等处理。
    5. 答主账号被删后赏金凭空消失(账目写着发放,全站积分一分没动):核心 user_points_change() 对不存在的用户是「静默成功」。发放 / 收回前先确认账号存在,不存在就明确拒绝,钱留在冻结池。
    6. 提问者账号被删后到期结算写假退款:改为 void 挂账核销(账目合计照样归零,但不谎称「已退回」),后台单独显示核销合计。
    7. 截止时刻与 settle 计划任务交错会超发(发 34 + 退 100 = 134,而悬赏只冻结 100):采纳 / 撤销的名额 CAS 补上截止时间守卫。

    新能力

    • 赏金加码:提问者与任何人都能给还开放的悬赏追加赏金,走同一条带守卫的 CAS 冻结扣款并落 freeze 账目;到期退款按各出资人的出资比例分摊(零头按出资先后补 1 分),分毫不差。
    • 到期提醒 + 自动催办:新增 remind 计划任务(每小时),两档(≤24 小时「最后催办」、≤ remind_days 天「到期提醒」),提醒提问者与尚未被采纳的答主;remind_stage 的 CAS 保证每档每人最多一条,后台可关。
    • 管理团队仲裁:暂缓结算(cron 跳过)/ 判定发放(不受截止时间限制,提问者失联也能裁决归属)/ 判定退回(按出资比例退还),全程写审计表(谁、何时、什么理由、动了哪笔钱),并通知双方。
    • 答主信誉榜:?a=qa_list&tab=answerers —— 被采纳数 / 采纳率 / 累计赏金,一条聚合查询算出,查询数与行数无关;匿名主题里的答主只显示「匿名答主」且不给主页链接。
    • 悬赏统计面板:待结算笔数、暂缓笔数、两个口径的冻结余额、累计加码、平均采纳时长、答主数、仲裁笔数、四类账目合计,并直接给出对账结论。

    升级与兼容

    • 老库自动升级(幂等补 4 列 + 新建审计表),卸载一并清理;原有 3 张表、资金口径、状态机、Hook、页面查询预算口径不变。
    • 六道静态门禁全绿;tools/lab_verify_qa.sh 扩到 366 项断言 / 0 失败。
    #3
  • cxk123

    版本 2.0.1 更新:
    2.0.1 修复:后台设置保存失败时看不到真正的错误原因

    • 校验失败时直接 fall through 成整页 HTML,而核心前端对这张表单走 fetch + JSON.parse → 用户只看到「操作失败」,真正的提示被吞掉。
    • 修法:AJAX 请求回 {"ok":0,"message":…} 信封;无 JS 浏览器仍是原来的整页渲染(字节不变)。
    • 首次补上 3 张预览图:悬赏榜(?a=qa_list)· 悬赏详情面板 + 赏金加码 · 管理团队仲裁(暂缓结算 / 判定退回 / 判定发放 + 仲裁审计)。
    #4
  • cxk123

    版本 2.0.2 更新:

    补丁版本:给「页面组件 DIY」加一个原生组件(未装 layout_diy 时行为逐字节不变)

    • 新增只读组件注册(私有 Hook diy_layout.components):具名渲染回调 + 声明查询成本 + 无数据时零查询降级(靠站点标记短路)+ 拿不到数据返回空串由宿主降级成占位(不抛异常,单块坏天气不会带走整页)。
    • 查询形状与行数无关:列表/映射/计数各一条批查,条数参数只改 LIMIT 的绑定值。
    • 组件自带参数白名单(条数 / 显示哪些字段),后台可视化编辑、越界值拒绝保存。
    • 未装「页面组件 DIY」时这个 Hook 无人调用:本插件的行为、查询数、页面字节与上一版逐字节一致(用「旧版 vs 新版、两边都停用 layout_diy」的 A/B 比对守着,含查询数)。
    #5
  • huaxiaoji

    这个看着不错。

    #6
  • cxk123

    版本 3.0.0 更新:

    3.0.0:全站列表页零查询 · 提问者控制台 · 悬赏订阅(+ 5 处缺陷修复)

    新增能力

    • 列表页 / 首页角标零查询:悬赏行 → 主题 id 的映射改存 app_settings 只读快照,核心在请求开头就把整张设置表读进内存 → 首页 / 版块 / 搜索 / 用户主题等所有列表页渲染「悬赏中 · 已解决」角标一次库都不用查(2.0.x 是每个列表页恒定 1 条 IN 批查)。快照由全部写路径就地维护、启用时重建、详情页发现漂移时自愈;悬赏超过 200 条自动回退整页批查(正确性优先)。
    • 提问者控制台 ?a=qa_close:提前结贴(已采纳的赏金不动,未发出的按出资比例退回给出资人,复用到期结算那条资金路径:同一套按比例退款、账号已注销走核销、同一批通知,状态转「已关闭 / 已退回」,写审计)与延期(1–30 天,总期限 ≤90 天,顺带复位催办阶段让新期限重新提醒)。只处理未结算的悬赏;管理团队「暂缓结算」期间提问者不能单方面结贴。
    • 悬赏订阅 + 变更通知:详情页订阅按钮(可勾「有新回答也通知我」)+ 列表页「我订阅的」页签;被采纳 / 加码 / 待结算变动时收到站内通知。页面路径只写一行事件(新表 plugin_qa_bounty_watch_events,UNIQUE(question_id,event_key) 幂等),由新增计划任务 watch(600 秒)扇出 —— 通知量与订阅人数不会落到页面请求上。一条消息只进一个人的收件箱一次:被采纳者不重复发、出资人已有退款通知就不重发、动作执行者与提问者不发。加码自动关注,退订留痕(之后加码不会把你加回来);单人订阅上限后台可调。
    • 后台新增「答案分页条数」(20–200,默认 100)与「单人订阅上限」(1–200,默认 50)两项设置。

    修复

    1. 列表页 / 首页每次渲染多 1 条 SQL → 只读快照后归零(实测:本插件启用与停用时首页查询数完全相同)。
    2. 「加码 ∥ 采纳」交错时末位赏金按旧总额结算,题目已「已解决」而冻结池里还压着钱、且没有任何路径再发出去 → 采纳路径在置「已解决」后再对一次账(末位名额取走池中剩余),settle 计划任务另加一层对账自愈(补发给最后一条被采纳的答案,账号已注销改挂账核销,全程写审计)。
    3. 答案列表硬上限 200 条且无分页 → 第 201 条起既看不到也无法被采纳(热帖赏金只能白挂到到期)→ 改为答案分页 + 「只看未采纳」筛选,总数取悬赏行上已有的列,没有额外 COUNT 查询。
    4. 回帖已被删除的「答案」仍可被采纳(钱发给一条不存在的内容)→ 采纳前校验回帖存在,不存在就明确拒绝并提示两条出路(改采纳别的答案 / 提前结贴退回)。
    5. 到期退款通知对加码人误称「你的悬赏」 → 按出资身份分派措辞。

    兼容

    • 老库自动升级:新增 2 张表 + 3 枚索引 + 1 条计划任务 + 1 个设置键,原 4 张表一列不动、历史账目与资金口径不变。
    • 卸载(连数据)会清干净新表 / 新索引 / 两个设置键;页面路径仍是循环体内零查库、三驱动可移植 SQL、写操作一律 POST + 令牌。
    #7
  • cxk123

    版本 3.1.0 更新:

    3.1.0:提问者管理台(批量结贴 / 延期 + 诚信分)· 真并发下的三处缺陷修复

    新增能力:提问者管理台 ?a=qa_manage

    • 一页看完「我的开放悬赏」,带呆滞标记:还没有人回答 / 有回答但快到期 / 结贴排队中 / 暂缓结算中 / 到点待结算。
    • 批量延期:勾选若干条一次提交(1–30 天,总期限按 90 天上限自动夹住),催办重新计时。
    • 批量结贴:勾选提交即入队(页面显示「结贴排队中」),由结算任务按出资比例把未发出的赏金退回给出资人;

    已采纳的部分不动;提交后还能「取消结贴」撤回。

    • 提问者诚信分:采纳率(已解决 ÷ 已结算,开放中不计入)、到期未采纳数、平均采纳时长、待结算 / 结贴排队中 ——

    全部由一条聚合查询算出。

    • 工程口径:批量动作对页面路径是 O(1)(延期一条 UPDATE、结贴只打标记,资金动作交给已有的结算任务),

    管理台查询数与悬赏条数无关(恒定 4 条)。

    修复(真并发实测抓出来的)

    1. 「加码 ∥ 采纳」交错后整个插件被核心自动停用:加码路径为了让事务回滚抛了未捕获异常,异常冒到核心 →

    核心按插件故障处置 → 之后所有悬赏页面 404(disabled_reason 记的就是 RuntimeException: 这条悬赏已经结束,加码未生效)。
    现在改成「内部哨兵 + 就地捕获」:回滚照旧,用户看到「这条悬赏刚刚被采纳或结算,加码没有生效(积分未扣)」,插件不受影响。

    1. 同类隐患一并收口:创建悬赏的事务在并发撞唯一约束或写入失败时也抛异常,而它跑在 topic.after_save 钩子里

    (钩子抛异常同样会停用插件)→ 现在就地消化成错误对象;topic.after_save / reply.after_save 两个钩子再加一层兜底。

    1. 详情页上管理团队的「仲裁发放」按钮永远渲染不出来(被提问者分支吃掉,只能拿到受截止时间限制的「采纳」)→

    改成按身份分派:提问者拿采纳/撤销,管理团队拿仲裁发放(不受截止时间限制,全程写审计)。

    硬证据(套件第 27–29 节)

    • 真并发:4 workers 站点上每轮「采纳 ∥ 加码」两条真并发请求,逐轮断言账目守恒 + 段末全站对账、零残留、

    插件未被停用、前台入口仍 200(这套断言就是上面缺陷 1 的发现者)。

    • 深分页:320 条答案 / 16 页 —— 第 16 页照样带采纳按钮并采纳成功、管理团队在第 14 页上仲裁发放成功、查询数与页深无关。
    • 预算复核:首页列表页对悬赏角标的贡献 0 条(启用态 = 停用态)、悬赏主题页净贡献恰好 2 条、管理台查询数不随条数增长。
    #8
  • cxk123

    版本 3.2.0 更新:
    3.2.0 · 覆盖升级自愈 + 对账余数

    • 修复(覆盖升级会砖):本插件此前只会在安装时建表/补列/建索引,而核心在覆盖文件时不重跑安装 ⇒ 老站点覆盖升级后首个查库操作就抛异常(PDOException)并被核心自动停用整个插件。现在补上运行期结构自愈:内存副本 → 设置标记 → 才做 DDL 的三道门,稳态零查询,15 个入口全部挂上(刻意不挂读钩子,以保持「与停用状态查询数完全一致」的既有预算口径)。
    • 修复(对账假账):悬赏对账自愈的「末位名额核销」分支只写账、不消解余数条件 ⇒ 同一条悬赏每轮结算都再记一笔核销,账目逐轮膨胀。现在核销同时消解余数,Σ已发 = 赏金 恒等式恢复。
    • 附带:卸载补删结构标记。

    升级:覆盖文件即自愈。

    #9
  • cxk123

    版本 3.3.0 更新:
    3.3.0 · 榜单与详情的版块可见性

    • 修复(越权):悬赏榜、悬赏详情、答主信誉榜与「高分榜」组件此前没有版块可见性判定 ⇒ 「仅指定用户组可见」版块里的悬赏,其主题标题会出现在公开榜单、详情与检索结果里。现在五处取数统一按核心同一口径过滤(管理团队作为该版块的合法访问者照常可见;公开版块内容不受影响)。
    • 口径:站内没有受限版块时,SQL 文本逐字节不变(既有性能与指纹断言不受影响);筛选/预算增量 0。
    #10
  • cxk123

    版本 3.4.0 更新:
    3.4.0 · 资金路径三连(采纳发放 / 并发金额 / 到期结算)+ 答主榜匿名遮蔽补齐

    • 修复(资金原子性 · 采纳与仲裁):采纳答案的三步 —— ①写 awarded 扣冻结池(含名额 CAS 与「已解决」置位)、②给答主打积分、③写 award 账目 —— 此前是三次独立提交。①之后 ②/③ 之前任何失败(进程中断、致命错误、积分入账抛异常)都会留下「池已扣、分未到、无账目」的半成品;题目此刻已置「已解决」,结算跳过、加码被挡,没有任何对账路径能发现它。现在三步包进同一事务,失败路径一律哨兵异常回滚(本仓库纪律:tx() 只在抛异常时回滚,用 return 会把半成品 COMMIT 掉),哨兵就地捕获、不外泄给核心(冒到核心会导致整插件被自动停用)。管理团队仲裁发放、以及同一资金链的对称路径「撤销采纳」走同一口径。
    • 修复(并发多发 · 末位名额):多名额悬赏里「末位名额取走池中全部」原先基于非原子读(SUM(awarded))且金额写回没有任何校验 ⇒ 两个并发采纳可以各读到旧余额、合计发出超过赏金总额(真实增发、冻结池被击穿),而末尾兜底在超发时算出负数被 max(0,…) 吞掉、不会自愈。现在金额写回收口为带 CAS 的抢占(期望值 = 本步读到的本行旧值,写完回读复核;抢不到就不再写第二遍),并在同一事务内补一道 Σ已发 ≤ 赏金 的不变量复核:越界部分从自己这一行收回。于是并发交错下最坏是「少付」而不是「多付」—— 少付的余数由结算对账补上,冻结池与站点积分总量都不会被击穿。
    • 修复(资金滞留 + 对账缺口):到期结算的状态推进只校验 status、退款又用读来的旧总额 ⇒「加码 ∥ 结算」交错时,后加的赏金按旧总额退款,差额永久滞留在冻结池(题目已成 2/3:加码被挡、结算不再处理它),而唯一的修复入口(对账自愈)当时只覆盖 status=1,够不着 2/3。现在状态推进的 CAS 一并校验 reward(打不中就让这条悬赏整轮顺延,下一轮按新总额重算 —— 加码与结算抢的是同一条 status=0 的语句,必有一方落空且干净回滚,加码人不会被扣钱);对账自愈的选择条件从 status=1 扩到 status IN (1,2,3):status=1 照旧「末位名额取走池中全部」,status 2/3 按 赏金 − Σ已发 − Σ(refund/void) 判真滞留并按出资比例退回(只看 赏金 − Σ已发 会把已经退过的钱再退一次,那是二次退款)。
    • 修复(隐私 · 匿名遮蔽只做了一半):答主信誉榜此前把匿名答主的显示名与主页链接遮掉了,但那一行的 data-qa-bounty-answerer 属性里仍写着真实用户 ID —— 看一次页面源码就能把「匿名答主」与真实账号对上号,与插件自身「不在榜单上把匿名答主与真实账号对上号」的设计口径直接矛盾。现在匿名行整条不输出该属性(公开行照旧输出,列表与后台排查不受影响);套件的断言也一并扩成「链接与真实 ID 都不得出现」并加了公开行同行反证。
    • 口径:三条资金修复只在失败 / 并发 / 交错路径上生效;正常单线程流程的金额、账目动作名(award / refund / void)、失败文案、通知文案与页面查询预算逐字节不变(结算任务文案只在新计数器真非零时追加一句)。新增写回全部是列与参数的比较(不写 表达式 < 参数),三驱动可移植、不含窗口函数,也没有在页面路径的循环体里查库 ——「重试」语义由事务与不变量复核承担,而不是靠循环重读。匿名修复只影响被遮蔽的那一行:公开行的 HTML 逐字节不变。
    • 升级:覆盖文件即可(表结构未变:无新增列 / 表 / 索引,不需要重跑安装)。
    #11
  • cxk123

    版本 3.4.1 更新:
    3.4.1 · 悬赏冻结/加码补齐标准积分事件(跨插件契约修复)

    • 修复(跨插件契约):提问冻结(qa_bounty_create())与加码冻结(qa_bounty_boost_route())用的是自带守卫的原子 CAS 扣款(points=points-? WHERE ... AND points>=?),没有经过核心的积分变动助手 ⇒ 不广播 user.points_changed。而赏金发放与退回是走助手的(会广播),于是同一笔悬赏在生态视角里是「进账有、出账无」—— 提问者的「积分净增」被高估整整一个赏金。
    • 现在:两处都在事务提交成功之后补发与核心同形的事件(event_key / user_id / delta / reason / points):
    • 冻结用 points-change:qa-bounty-freeze:<问题 id>;加码用账目行 id(points-change:qa-bounty-bump:<ledger_id>)——

    特意不用问题 id:同一道悬赏可以多次加码,用问题 id 会被下游按 event_key 去重吞掉第二笔;

    • 扣款没成功(余额不足)与竞态回滚(加码撞采纳/结算)一条事件都不发,与"钱没动过"保持一致。
    • 不发第二次:发放/退回/仲裁/对账这些已经走核心助手的路径一个字未改 —— 本次只补那两处冻结,避免同一笔钱被广播两次。
    • 对本站:不开新表、不加新列、不改任何页面文案与可见行为。
    #12

发表回复

登录后回复