u3oq`$(*_^F#UGhjHM&dcjHSNe>8bnZj^_Tlg$3ej
z#ct6Q(YOs|*4+}gFpOLqD14|E3X`}JJtjx8_#%KFfJ@;bOk?PZ+j8~Tpt
zK7i(5yX@KkAf3@!IHPg){Z_OZ+S{P65n5_RRM7-AkO>{*mr8rr
zArs~m1j)u2uTKN1-F+w5JT-obGCyge<`_8G@`3qLYvwvDCQV{|?SxkRn8bTELv8A7
z{_m?)spRR`H>mIy_Y7Zah%wyCV_mnLvva!07^yvX=>}q!ujzC87r7Vv9*DMHNntH$
z-)OU{mKgEwFM*L;)mk1t`fKKFS>n|*A+
z#Cgrk-DvO9QqQ<
zek&6b!JK_6T#35sQap^Vh{$OrZMs(btMJ|`{z)CyKB_1*4RLmchjL%GZb4WlZ$|%k
z`H!FLWJsB7wYylGTOYU^7Hr>&iJ-m2uM1KT+uC|sr&pZy2aV}2m&;y-nmYE;B(2wL
z1=I{WkaVQ#h7U?)3mLEHIOYqWGRW{idAYCLtD=Prb(9D}rc
z*{?iHUsgdvER;TKCmgHNvXZ%69)OTS`ZP$T*vIq*xwn6*ZhvZvXDLTWUT?R!QK3uPEnQ_;bOvHBI&p1C;
zk~}UmN66(p3S_RMvpI~$+0Lgn#BG~|d{Rw6b8PZhM+Re7w_@$d>gpGlYM<#s5^p5R
z?X*148Y-`Mj$t_WiC&ufde)9XB+~Kp{zn^;QJfe9<$R+{rq8?g%^=P$nCK?s6lXqm
zy>VsQuoLz*k_Z)u&N4NXzqi+2&`%=TN6Kg@ssrg#ZR6Kr+J3-X@Q;!Xo|G{P7N6_e`&tkOIpmNJY|Z^Hw*kFTa=Hzwp6@3
zru}mHx1D!Cj)kPhQAcJ)v_SMvf!rYk#eCBzG;6B48yAajpS8EM7^s-^tT1P;Pm)L=
zB{k@O7KyOW+V$%hWWYwhD-q@KV(wce`MuGCklvS$rfP0B_`OmsI@@|{zA;2@J4*Bo
z{zP5G$geQ^z4E82x5-TYviSME~|WBaZuHAXoh2(
z?oqlYSCvxE)-QfLtLOssH$_v3`a2}I);}fvPX7UCIhzfw$;1`!@+Zr*dA7KlKD>`4
zPTb~=!AB&KAEzBTIDTn<4}(z&jlv%Dp`kcPs0d%4C96iWKn1_oGDT35H&;B(>cV+J
zj2=WEa!cb}6~pJ(8P$0VLHInQ?sVs~L|!W)oZt#yrr`m(Z*O8vVySzpdv4fuK5l7A
zJURWWEnLo{Okt66fTxY7
zRO;{C_TBmPyV7l^AD%YS)ynY~GqyR*Nm0B@^K3qu&N4dM)jYB@4RijB{{58Vvt$vs
zBmR#d=`jEykD&B#xodzU=@+{0=i65r$(5rQtHgEZta#fja$SzxuQ!;*{AA)|{-|{!
zGlvSnz9sf*%PRvqH=kF8FZ@i2uT(#*etXAb4M8L0gl@X0X;X=}MSP~>fQ%tO5Hs*WN%tUC_}8%FXG>$~}(}Rp^n@f%QxHGn^N{
zJ{s~5LT2qOI*Q#(H>tz`Sv2=poYg7l&sGrwD^(d)WuQ`-ZJ>#@cPtWQ~
z#CV~voug5?>4=(u>f_ziAj$eD?1ZmYQn20sm
zc(>9V{E5ac%#%s@o=2(}wGs~tq&70b*ZDw)2mYF%jL3=Dnr&4k*PX(A^WS2QINrZq
ze>C;y(E@#@`SagcC=ar-j%Erz=9egew{052J5A
z35}qddY34E{pHGhY^Ac!!q471XxFZ=yp*o!TsqDvDW#z|vAkO9mmeSXkWg!j3MR*s
z0Tei*-L|&O-$yhx^>Y(`qZ!d?IC_fRk_oTQq$o?;+iz4}(P>r6FiJO6iZcFrE8#6s
zjyiuBhCt+;+0rImr_kn?gXZ(d=dLsL=8$%}#HnWy(hD_vv$EeX!LBYkU9BrRmw48U({pCR2S){
zPOKO|U%@-`&OQ0{+1ckJUk{30ncww5zL<(3^L0O0g{@5>o4>Db4lOFr|He0^RxX_-s(S{mNp{&0bQAVf7+WXoMy)hxAI+!S@hojmmB
zygw`aWkVB@)3O!hbOv`jAvxIwT3_KZX3gY8Tg-^w)!c}k-0S*}qsaafR40N?3m8{+
z=f{>InXpi0JoE^DXah^4b<4TIe}~#Hf=XVm)()3eafqkv6wR!0MDlHpj?-p!Uv^A5
z*LGa@Fvp
zUa}&tC9iPWHyZDGpVl0?oXp=*T$_8u>y;OF#M)jo$5dmKC%nxdTA81%%t}qbW6G(u
z-RLq)z4iR<`)#$+7HVB@pf6rgLthgb;ZI3ubk2Klq-}0Xp41f;$;r9%uF{Hn(5Q?S$R^Z*L0<
zNh2vOImHpE-UOM1xlg#Dgyb7#J{E#cf*H<MBx*`9i7eguNy2ib^XFK!qB=J
zmxTK&rb&!ff@3+v5H0=|yrk_koU|z32zvSBZU>k8{v%>@FBJFg(O4ng0Lefhr7mTEZrbzyE_LwZtzA~3*UJ}_AXj&~GO1b`A
z=b&6?=#ksiO>7w1l@=O0Y?+upqtchygkzQOV;3}$00A65CR_6)NQUMM(?;UJQ|<8O
z%xW{9;SxVat>^6F2UC$k7Z2%nKJMbX$7Gwmaz+S&C$ct}-i@WRe59n3CKc<1{=WV=C5~
z$f|4C%^vKDe@i=1HTosD+|+r9x6kl)+AYXAHSA#1(u4iA&(7_+#@-&r7!05l(G-`-s|;7c_1@@s)B6=ZM9#^qE}Hh~WmHGiA)3W1;n#FufuJ~oa%tO+
zKs-Y1n>4|=-QD1-!`sS_>}PolowPhVvp!phtLz;E%!cUfv_A}hATFW8k-H7GIl=xl
z@oej|6GY!^?IAPp6Z}A5`3mq+#1TPUyG^OHq>SxODjT(J25^CM3wf?Cfk^+nnzPk#DU001KJ
zax-w?Gsdp_5yi@$Ei5DR9Gs!&)=J}IR_P>*-`TTR-1``doS-kLx$mL_WF!!jzD;Xk
znf)AvqJf>5*&u2=r-KHe8)eUb5cSdFVuQK{%Z5F$j>pm2ga2kPr_k#;#9>m~I$~y5
zXMaVr`+6VLxW@f3o(}a!z_SsXykx3xWn!MPe(WUs;cDp;+eZ3quJS9+K`b12RO<24
zJT;0oqe%mRS3^@){&oR-oY8xs*E>=b$>X|~0yb$>G<-E5GFxjZCa&uGm%DyS`p8~O
zPV{s!QnS410Hmc6IlF$_zcXdPkW+5R_g6&i@}5z(JC0^+>lc}^H5($kr+TCcFNh_;
z=7=J4cK^1XyJ6lkdQ45yBrrK8H_Amo<`t9qfv!?pQ+vR86rIKYZ+7pX6ke-)5R)fA
z(#CXV_Pw^NN?*E}x3XZXx}gfx6?(eO=0v=hR>dy{9pP5*Kp*~(bSc<7?L##OYI_L4
z-SDQawmn5bbtfJ3=uL$y%eceIA3ir8jCLwJ{epgHDVdqM+VNq!ba`A`nNpTd3d{4L
zcB3;I4KqeZ;m_pYPI~+=3w%1dCkl^Ar@hENobK!(6*{sv0^3!4Wr27ZQ_V=ObA?Y5
zV|13zwk5&a4<`_`Lnyc9Q)bph&W{ju(<`Bct!JZYaw*hss{CQEOVGDsyE|^^usUtQ
zZk)|S8^yk*3h%lRsXTzDjn0YqJ78?D_{=3Wrg(P$W6s(bmss`A*03)RUphr|=p?Nb
znY~Y8(2Un1L|2U103aj~IoEzijhpnZvo`X9nsbBvGETGvvnxmsmkQW*5IL0J26Ig_
zcW1n`KQ3>C5bvQVakUv&<Su6x_ewdinZ7
z^}t$LRa&2-U<%;?LtN_DV=ck6D4ozz^!XTuw0!_s1)Y=s4}TosGnY02?@biwMNghd
z(usPBYMvwEM}EF74*&kV>sd>##@@@teT}(#@bLsJYy9m9E_<12JH8IV$MsI9+OCEk
zeTX)5e@3!^N-IWKavb?L@~E85c-uXgoe!Kd-60_rlIclXUY)4tD)Wdm!<>yuffdcq|S5(EjoJ=nK&=Fc!|)p*h?^zedh|cdKD$cHx{GX!EmK7Zu@X+&9&fO7@=WSXBQX
D1sMe3
literal 0
HcmV?d00001
diff --git a/challenge-withdrawal-reimbursement-guard/reports/risky-withdrawal-handoff.md b/challenge-withdrawal-reimbursement-guard/reports/risky-withdrawal-handoff.md
new file mode 100644
index 00000000..3bd0796f
--- /dev/null
+++ b/challenge-withdrawal-reimbursement-guard/reports/risky-withdrawal-handoff.md
@@ -0,0 +1,35 @@
+# Challenge Withdrawal Reimbursement Handoff
+
+Decision: escalate_withdrawal_dispute
+Affected solvers: 3
+Recommended reimbursement: $2586.00
+Funded shortfall: $2286.00
+Audit digest: sha256:af101fe0baa90544d8acc9069ccfa1524ccfc6c133806eeff1bb088088a48cb1
+
+## Priority Findings
+
+| Severity | Code | Remediation |
+| --- | --- | --- |
+| critical | CANCELLATION_AUTHORITY_MISSING | verify_sponsor_cancellation_authority_before_closeout |
+| critical | DISPUTE_HOLD_WINDOW_TOO_SHORT | extend_dispute_hold_before_refund_or_closeout |
+| critical | REIMBURSEMENT_RESERVE_SHORTFALL | fund_solver_reimbursement_reserve_before_releasing_sponsor_refund |
+| high | APPEAL_DEADLINE_MISSING | set_solver_appeal_deadline_before_withdrawal_closeout |
+| high | COST_CLAIM_EVIDENCE_MISSING | attach_cost_claim_evidence_before_reimbursement |
+| high | COST_CLAIM_PATH_NOT_IN_NOTICE | include_solver_cost_claim_path_in_notice |
+| high | MILESTONE_EVIDENCE_HASH_MISSING | hash_milestone_evidence_before_solver_cost_review |
+| high | NONREFUNDABLE_RECEIPT_MISSING | attach_receipt_hash_for_nonrefundable_solver_spend |
+| high | NONREFUNDABLE_RECEIPT_MISSING | attach_receipt_hash_for_nonrefundable_solver_spend |
+| high | NONREFUNDABLE_RECEIPT_MISSING | attach_receipt_hash_for_nonrefundable_solver_spend |
+| high | NOTICE_PARITY_GAP | restart_closeout_clock_after_equal_solver_notice |
+| high | REIMBURSEMENT_DECISION_MISSING | record_solver_reimbursement_decision_before_challenge_closeout |
+
+## Team Recommendations
+
+### BNTY-WITHDRAW-RISK
+
+| Team | Recommended | Recorded | Shortfall | Action |
+| --- | ---: | ---: | ---: | --- |
+| team-lovelace | $1449.00 | $500.00 | $949.00 | hold_and_reimburse_solver_costs |
+| team-hopper | $634.00 | $0.00 | $634.00 | hold_and_reimburse_solver_costs |
+| team-johnson | $503.00 | $0.00 | $503.00 | hold_and_reimburse_solver_costs |
+
diff --git a/challenge-withdrawal-reimbursement-guard/reports/risky-withdrawal-report.json b/challenge-withdrawal-reimbursement-guard/reports/risky-withdrawal-report.json
new file mode 100644
index 00000000..1c304c62
--- /dev/null
+++ b/challenge-withdrawal-reimbursement-guard/reports/risky-withdrawal-report.json
@@ -0,0 +1,266 @@
+{
+ "summary": {
+ "decision": "escalate_withdrawal_dispute",
+ "challengeCount": 1,
+ "affectedSolvers": 3,
+ "recommendedReimbursementUsd": 2586,
+ "fundedShortfallUsd": 2286,
+ "findingCount": 21,
+ "criticalFindings": 3,
+ "highOrCriticalFindings": 15,
+ "auditDigest": "sha256:af101fe0baa90544d8acc9069ccfa1524ccfc6c133806eeff1bb088088a48cb1"
+ },
+ "challenges": [
+ {
+ "id": "BNTY-WITHDRAW-RISK",
+ "status": "canceled",
+ "bountyAmountUsd": 9000,
+ "action": "hold_for_solver_reimbursement",
+ "affectedSolvers": 3,
+ "recommendedReimbursementUsd": 2586,
+ "fundedShortfallUsd": 2286,
+ "recommendations": [
+ {
+ "teamId": "team-lovelace",
+ "documentedCostsUsd": 720,
+ "irreversibleCostsUsd": 720,
+ "milestoneCreditUsd": 729,
+ "reimbursementCapUsd": 2600,
+ "recommendedUsd": 1449,
+ "recordedUsd": 500,
+ "shortfallUsd": 949,
+ "action": "hold_and_reimburse_solver_costs"
+ },
+ {
+ "teamId": "team-hopper",
+ "documentedCostsUsd": 310,
+ "irreversibleCostsUsd": 310,
+ "milestoneCreditUsd": 324,
+ "reimbursementCapUsd": 2600,
+ "recommendedUsd": 634,
+ "recordedUsd": 0,
+ "shortfallUsd": 634,
+ "action": "hold_and_reimburse_solver_costs"
+ },
+ {
+ "teamId": "team-johnson",
+ "documentedCostsUsd": 260,
+ "irreversibleCostsUsd": 260,
+ "milestoneCreditUsd": 243,
+ "reimbursementCapUsd": 2600,
+ "recommendedUsd": 503,
+ "recordedUsd": 0,
+ "shortfallUsd": 503,
+ "action": "hold_and_reimburse_solver_costs"
+ }
+ ]
+ }
+ ],
+ "findings": [
+ {
+ "severity": "critical",
+ "code": "CANCELLATION_AUTHORITY_MISSING",
+ "message": "BNTY-WITHDRAW-RISK does not show a sponsor-authorized cancellation decision.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK"
+ ],
+ "action": "verify_sponsor_cancellation_authority_before_closeout"
+ },
+ {
+ "severity": "critical",
+ "code": "DISPUTE_HOLD_WINDOW_TOO_SHORT",
+ "message": "BNTY-WITHDRAW-RISK has a dispute hold of 4 days.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK"
+ ],
+ "action": "extend_dispute_hold_before_refund_or_closeout"
+ },
+ {
+ "severity": "critical",
+ "code": "REIMBURSEMENT_RESERVE_SHORTFALL",
+ "message": "BNTY-WITHDRAW-RISK reserve is short by $2286.00 for solver reimbursement.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK"
+ ],
+ "action": "fund_solver_reimbursement_reserve_before_releasing_sponsor_refund"
+ },
+ {
+ "severity": "high",
+ "code": "APPEAL_DEADLINE_MISSING",
+ "message": "BNTY-WITHDRAW-RISK has no solver appeal deadline.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK"
+ ],
+ "action": "set_solver_appeal_deadline_before_withdrawal_closeout"
+ },
+ {
+ "severity": "high",
+ "code": "COST_CLAIM_EVIDENCE_MISSING",
+ "message": "team-lovelace cost claim annotation-vendor lacks evidence.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-lovelace"
+ ],
+ "action": "attach_cost_claim_evidence_before_reimbursement"
+ },
+ {
+ "severity": "high",
+ "code": "COST_CLAIM_PATH_NOT_IN_NOTICE",
+ "message": "team-lovelace notice omits the cost-claim path.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-lovelace"
+ ],
+ "action": "include_solver_cost_claim_path_in_notice"
+ },
+ {
+ "severity": "high",
+ "code": "MILESTONE_EVIDENCE_HASH_MISSING",
+ "message": "team-lovelace milestone baseline-model lacks an evidence hash.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-lovelace"
+ ],
+ "action": "hash_milestone_evidence_before_solver_cost_review"
+ },
+ {
+ "severity": "high",
+ "code": "NONREFUNDABLE_RECEIPT_MISSING",
+ "message": "team-lovelace non-refundable cost claim gpu-reservation lacks a receipt hash.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-lovelace"
+ ],
+ "action": "attach_receipt_hash_for_nonrefundable_solver_spend"
+ },
+ {
+ "severity": "high",
+ "code": "NONREFUNDABLE_RECEIPT_MISSING",
+ "message": "team-lovelace non-refundable cost claim annotation-vendor lacks a receipt hash.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-lovelace"
+ ],
+ "action": "attach_receipt_hash_for_nonrefundable_solver_spend"
+ },
+ {
+ "severity": "high",
+ "code": "NONREFUNDABLE_RECEIPT_MISSING",
+ "message": "team-hopper non-refundable cost claim secure-workspace lacks a receipt hash.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-hopper"
+ ],
+ "action": "attach_receipt_hash_for_nonrefundable_solver_spend"
+ },
+ {
+ "severity": "high",
+ "code": "NOTICE_PARITY_GAP",
+ "message": "team-hopper received withdrawal notice 20 hours after the first notified solver.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-hopper"
+ ],
+ "action": "restart_closeout_clock_after_equal_solver_notice"
+ },
+ {
+ "severity": "high",
+ "code": "REIMBURSEMENT_DECISION_MISSING",
+ "message": "team-hopper has an eligible reimbursement recommendation but no recorded decision.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-hopper"
+ ],
+ "action": "record_solver_reimbursement_decision_before_challenge_closeout"
+ },
+ {
+ "severity": "high",
+ "code": "REIMBURSEMENT_DECISION_MISSING",
+ "message": "team-johnson has an eligible reimbursement recommendation but no recorded decision.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-johnson"
+ ],
+ "action": "record_solver_reimbursement_decision_before_challenge_closeout"
+ },
+ {
+ "severity": "high",
+ "code": "REIMBURSEMENT_SHORTFALL",
+ "message": "team-lovelace reimbursement is short by $949.00.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-lovelace"
+ ],
+ "action": "fund_reimbursement_shortfall_or_escalate_dispute"
+ },
+ {
+ "severity": "high",
+ "code": "SOLVER_WITHDRAWAL_NOTICE_MISSING",
+ "message": "team-johnson has no direct withdrawal notice.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-johnson"
+ ],
+ "action": "send_equal_withdrawal_notice_to_all_started_solvers"
+ },
+ {
+ "severity": "medium",
+ "code": "APPEAL_WINDOW_NOT_IN_NOTICE",
+ "message": "team-lovelace notice omits the appeal window.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-lovelace"
+ ],
+ "action": "include_appeal_deadline_in_solver_notice"
+ },
+ {
+ "severity": "medium",
+ "code": "APPEAL_WINDOW_NOT_IN_NOTICE",
+ "message": "team-hopper notice omits the appeal window.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-hopper"
+ ],
+ "action": "include_appeal_deadline_in_solver_notice"
+ },
+ {
+ "severity": "medium",
+ "code": "IP_DATA_RETURN_ATTESTATION_MISSING",
+ "message": "team-lovelace has no complete IP return and data-destruction attestation.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-lovelace"
+ ],
+ "action": "collect_ip_return_and_data_destruction_attestation"
+ },
+ {
+ "severity": "medium",
+ "code": "IP_DATA_RETURN_ATTESTATION_MISSING",
+ "message": "team-hopper has no complete IP return and data-destruction attestation.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-hopper"
+ ],
+ "action": "collect_ip_return_and_data_destruction_attestation"
+ },
+ {
+ "severity": "medium",
+ "code": "IP_DATA_RETURN_ATTESTATION_MISSING",
+ "message": "team-johnson has no complete IP return and data-destruction attestation.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK",
+ "team-johnson"
+ ],
+ "action": "collect_ip_return_and_data_destruction_attestation"
+ },
+ {
+ "severity": "medium",
+ "code": "WITHDRAWAL_REASON_TOO_THIN",
+ "message": "BNTY-WITHDRAW-RISK has no reviewer-ready reason for withdrawal or material reduction.",
+ "refs": [
+ "BNTY-WITHDRAW-RISK"
+ ],
+ "action": "record_specific_withdrawal_reason_for_audit"
+ }
+ ]
+}
diff --git a/challenge-withdrawal-reimbursement-guard/reports/withdrawal-dashboard.svg b/challenge-withdrawal-reimbursement-guard/reports/withdrawal-dashboard.svg
new file mode 100644
index 00000000..fe101681
--- /dev/null
+++ b/challenge-withdrawal-reimbursement-guard/reports/withdrawal-dashboard.svg
@@ -0,0 +1,29 @@
+
diff --git a/challenge-withdrawal-reimbursement-guard/sample-data.js b/challenge-withdrawal-reimbursement-guard/sample-data.js
new file mode 100644
index 00000000..f2482b72
--- /dev/null
+++ b/challenge-withdrawal-reimbursement-guard/sample-data.js
@@ -0,0 +1,274 @@
+const cleanPacket = {
+ reviewDate: "2026-06-01",
+ policy: {
+ equalNoticeToleranceHours: 12,
+ disputeHoldDays: 10,
+ maxReimbursementPercent: 0.35,
+ materialReductionThresholdPercent: 25,
+ milestoneCreditRate: 0.18,
+ irreversibleSpendRequiresReceipt: true,
+ requireSponsorFundedReserve: true
+ },
+ challenges: [
+ {
+ id: "BNTY-WITHDRAW-ALPHA",
+ title: "Federated reproducibility benchmark",
+ status: "withdrawn",
+ sponsor: {
+ id: "sponsor-lab-a",
+ cancellationAuthority: true,
+ reimbursementReserveUsd: 2200
+ },
+ bounty: {
+ amountUsd: 6000,
+ reimbursementCapUsd: 2100
+ },
+ cancellation: {
+ type: "withdrawal",
+ requestedAt: "2026-05-28T15:00:00Z",
+ effectiveAt: "2026-06-07T15:00:00Z",
+ reason: "Sponsor lost access to the proprietary validation corpus and withdrew before finalist scoring.",
+ authorizedBy: "sponsor-owner-17",
+ materialReductionPercent: 100,
+ appealDeadline: "2026-06-06T15:00:00Z",
+ disputeHoldUntil: "2026-06-08T15:00:00Z"
+ },
+ communications: {
+ sponsorNoticeAt: "2026-05-28T15:10:00Z",
+ solverNotices: [
+ {
+ teamId: "team-curie",
+ sentAt: "2026-05-28T15:15:00Z",
+ channel: "platform",
+ includesAppealWindow: true,
+ includesCostClaimLink: true
+ },
+ {
+ teamId: "team-noether",
+ sentAt: "2026-05-28T16:00:00Z",
+ channel: "platform",
+ includesAppealWindow: true,
+ includesCostClaimLink: true
+ }
+ ]
+ },
+ solvers: [
+ {
+ teamId: "team-curie",
+ acceptedAt: "2026-05-20T12:00:00Z",
+ startedAt: "2026-05-21T09:00:00Z",
+ milestoneProgressPercent: 42,
+ submittedMilestones: [
+ { id: "design-review", percent: 25, evidenceHash: "sha256:curie-design-review-0a1b2c3d4e" },
+ { id: "baseline-run", percent: 17, evidenceHash: "sha256:curie-baseline-run-0a1b2c3d4e" }
+ ],
+ costClaims: [
+ {
+ id: "cloud-prep",
+ amountUsd: 180,
+ category: "compute",
+ incurredAt: "2026-05-25",
+ nonRefundable: true,
+ evidenceHash: "sha256:curie-cloud-evidence-0a1b2c3d4e",
+ receiptHash: "sha256:curie-cloud-receipt-0a1b2c3d4e"
+ }
+ ],
+ ipReturn: {
+ returnedAt: "2026-05-30T12:00:00Z",
+ dataDestroyedAt: "2026-05-30T12:15:00Z",
+ attestationHash: "sha256:curie-return-attestation-0a1b2c3d4e"
+ }
+ },
+ {
+ teamId: "team-noether",
+ acceptedAt: "2026-05-22T13:30:00Z",
+ startedAt: "2026-05-23T10:00:00Z",
+ milestoneProgressPercent: 28,
+ submittedMilestones: [
+ { id: "replication-plan", percent: 28, evidenceHash: "sha256:noether-plan-evidence-0a1b2c3d4e" }
+ ],
+ costClaims: [
+ {
+ id: "dataset-access",
+ amountUsd: 140,
+ category: "data",
+ incurredAt: "2026-05-24",
+ nonRefundable: true,
+ evidenceHash: "sha256:noether-data-evidence-0a1b2c3d4e",
+ receiptHash: "sha256:noether-data-receipt-0a1b2c3d4e"
+ }
+ ],
+ ipReturn: {
+ returnedAt: "2026-05-30T13:00:00Z",
+ dataDestroyedAt: "2026-05-30T13:20:00Z",
+ attestationHash: "sha256:noether-return-attestation-0a1b2c3d4e"
+ }
+ }
+ ],
+ reimbursements: [
+ {
+ teamId: "team-curie",
+ amountUsd: 633.60,
+ approvedBy: "bounty-ops",
+ approvedAt: "2026-05-31T10:00:00Z"
+ },
+ {
+ teamId: "team-noether",
+ amountUsd: 442.40,
+ approvedBy: "bounty-ops",
+ approvedAt: "2026-05-31T10:05:00Z"
+ }
+ ]
+ }
+ ]
+};
+
+const riskyPacket = {
+ reviewDate: "2026-06-01",
+ policy: {
+ equalNoticeToleranceHours: 8,
+ disputeHoldDays: 10,
+ maxReimbursementPercent: 0.35,
+ materialReductionThresholdPercent: 25,
+ milestoneCreditRate: 0.18,
+ irreversibleSpendRequiresReceipt: true,
+ requireSponsorFundedReserve: true
+ },
+ challenges: [
+ {
+ id: "BNTY-WITHDRAW-RISK",
+ title: "Private clinical signal challenge",
+ status: "canceled",
+ sponsor: {
+ id: "sponsor-clinic-x",
+ cancellationAuthority: false,
+ reimbursementReserveUsd: 300
+ },
+ bounty: {
+ amountUsd: 9000,
+ reimbursementCapUsd: 2600
+ },
+ cancellation: {
+ type: "cancellation",
+ requestedAt: "2026-05-29T11:00:00Z",
+ effectiveAt: "2026-05-30T11:00:00Z",
+ reason: "Budget changed",
+ materialReductionPercent: 100,
+ disputeHoldUntil: "2026-06-02T11:00:00Z"
+ },
+ communications: {
+ sponsorNoticeAt: "2026-05-29T12:00:00Z",
+ solverNotices: [
+ {
+ teamId: "team-lovelace",
+ sentAt: "2026-05-29T13:00:00Z",
+ channel: "email",
+ includesAppealWindow: false,
+ includesCostClaimLink: false
+ },
+ {
+ teamId: "team-hopper",
+ sentAt: "2026-05-30T09:00:00Z",
+ channel: "email",
+ includesAppealWindow: false,
+ includesCostClaimLink: true
+ }
+ ]
+ },
+ solvers: [
+ {
+ teamId: "team-lovelace",
+ acceptedAt: "2026-05-20T12:00:00Z",
+ startedAt: "2026-05-21T08:00:00Z",
+ milestoneProgressPercent: 45,
+ submittedMilestones: [
+ { id: "baseline-model", percent: 35, evidenceHash: "" },
+ { id: "validation-report", percent: 10, evidenceHash: "sha256:lovelace-report-evidence-0a1b2c3d4e" }
+ ],
+ costClaims: [
+ {
+ id: "gpu-reservation",
+ amountUsd: 720,
+ category: "compute",
+ incurredAt: "2026-05-24",
+ nonRefundable: true,
+ evidenceHash: "sha256:lovelace-gpu-evidence-0a1b2c3d4e",
+ receiptHash: ""
+ },
+ {
+ id: "annotation-vendor",
+ amountUsd: 420,
+ category: "annotation",
+ incurredAt: "2026-05-25",
+ nonRefundable: true,
+ evidenceHash: "",
+ receiptHash: ""
+ }
+ ],
+ ipReturn: {
+ returnedAt: "",
+ dataDestroyedAt: "",
+ attestationHash: ""
+ }
+ },
+ {
+ teamId: "team-hopper",
+ acceptedAt: "2026-05-22T10:00:00Z",
+ startedAt: "2026-05-23T09:00:00Z",
+ milestoneProgressPercent: 20,
+ submittedMilestones: [],
+ costClaims: [
+ {
+ id: "secure-workspace",
+ amountUsd: 310,
+ category: "workspace",
+ incurredAt: "2026-05-24",
+ nonRefundable: true,
+ evidenceHash: "sha256:hopper-workspace-evidence-0a1b2c3d4e",
+ receiptHash: ""
+ }
+ ],
+ ipReturn: null
+ },
+ {
+ teamId: "team-johnson",
+ acceptedAt: "2026-05-23T10:00:00Z",
+ startedAt: "2026-05-24T09:00:00Z",
+ milestoneProgressPercent: 15,
+ submittedMilestones: [
+ { id: "error-analysis", percent: 15, evidenceHash: "sha256:johnson-error-analysis-0a1b2c3d4e" }
+ ],
+ costClaims: [
+ {
+ id: "dataset-license",
+ amountUsd: 260,
+ category: "data",
+ incurredAt: "2026-05-25",
+ nonRefundable: true,
+ evidenceHash: "sha256:johnson-license-evidence-0a1b2c3d4e",
+ receiptHash: "sha256:johnson-license-receipt-0a1b2c3d4e"
+ }
+ ],
+ ipReturn: {
+ returnedAt: "2026-05-31T12:00:00Z",
+ dataDestroyedAt: "",
+ attestationHash: ""
+ }
+ }
+ ],
+ reimbursements: [
+ {
+ teamId: "team-lovelace",
+ amountUsd: 500,
+ approvedBy: "sponsor-admin",
+ approvedAt: "2026-05-30T12:00:00Z"
+ }
+ ]
+ }
+ ]
+};
+
+module.exports = {
+ cleanPacket,
+ riskyPacket
+};
diff --git a/challenge-withdrawal-reimbursement-guard/test.js b/challenge-withdrawal-reimbursement-guard/test.js
new file mode 100644
index 00000000..c376b33a
--- /dev/null
+++ b/challenge-withdrawal-reimbursement-guard/test.js
@@ -0,0 +1,44 @@
+const assert = require("node:assert/strict");
+const { evaluateChallengeWithdrawal, sha256 } = require("./index");
+const { cleanPacket, riskyPacket } = require("./sample-data");
+
+const clean = evaluateChallengeWithdrawal(cleanPacket);
+assert.equal(clean.summary.decision, "release_withdrawal_closeout");
+assert.equal(clean.summary.findingCount, 0);
+assert.equal(clean.summary.challengeCount, 1);
+assert.equal(clean.summary.affectedSolvers, 2);
+assert.equal(clean.summary.recommendedReimbursementUsd, 1076);
+assert.equal(clean.summary.fundedShortfallUsd, 0);
+assert.ok(clean.summary.auditDigest.startsWith("sha256:"));
+assert.equal(clean.challenges[0].action, "release_withdrawal_closeout");
+
+const risky = evaluateChallengeWithdrawal(riskyPacket);
+assert.equal(risky.summary.decision, "escalate_withdrawal_dispute");
+assert.equal(risky.summary.challengeCount, 1);
+assert.equal(risky.summary.affectedSolvers, 3);
+assert.equal(risky.summary.recommendedReimbursementUsd, 2586);
+assert.equal(risky.summary.fundedShortfallUsd, 2286);
+assert.ok(risky.summary.findingCount >= 17);
+assert.ok(risky.summary.criticalFindings >= 3);
+assert.ok(risky.summary.highOrCriticalFindings >= 12);
+
+const findingCodes = new Set(risky.findings.map((finding) => finding.code));
+assert.ok(findingCodes.has("CANCELLATION_AUTHORITY_MISSING"));
+assert.ok(findingCodes.has("SOLVER_WITHDRAWAL_NOTICE_MISSING"));
+assert.ok(findingCodes.has("NOTICE_PARITY_GAP"));
+assert.ok(findingCodes.has("COST_CLAIM_PATH_NOT_IN_NOTICE"));
+assert.ok(findingCodes.has("MILESTONE_EVIDENCE_HASH_MISSING"));
+assert.ok(findingCodes.has("COST_CLAIM_EVIDENCE_MISSING"));
+assert.ok(findingCodes.has("NONREFUNDABLE_RECEIPT_MISSING"));
+assert.ok(findingCodes.has("REIMBURSEMENT_SHORTFALL"));
+assert.ok(findingCodes.has("REIMBURSEMENT_DECISION_MISSING"));
+assert.ok(findingCodes.has("DISPUTE_HOLD_WINDOW_TOO_SHORT"));
+assert.ok(findingCodes.has("REIMBURSEMENT_RESERVE_SHORTFALL"));
+assert.ok(findingCodes.has("IP_DATA_RETURN_ATTESTATION_MISSING"));
+
+const firstDigest = evaluateChallengeWithdrawal(riskyPacket).summary.auditDigest;
+const secondDigest = evaluateChallengeWithdrawal(riskyPacket).summary.auditDigest;
+assert.equal(firstDigest, secondDigest);
+assert.equal(sha256({ b: 2, a: 1 }), sha256({ a: 1, b: 2 }));
+
+console.log("challenge withdrawal reimbursement guard tests passed");
diff --git a/challenge-withdrawal-reimbursement-guard/verify-video.js b/challenge-withdrawal-reimbursement-guard/verify-video.js
new file mode 100644
index 00000000..39af983c
--- /dev/null
+++ b/challenge-withdrawal-reimbursement-guard/verify-video.js
@@ -0,0 +1,37 @@
+const assert = require("node:assert/strict");
+const fs = require("node:fs");
+const path = require("node:path");
+const { spawnSync } = require("node:child_process");
+
+const videoPath = path.join(__dirname, "reports", "demo.mp4");
+assert.ok(fs.existsSync(videoPath), "reports/demo.mp4 must exist");
+assert.ok(fs.statSync(videoPath).size > 5000, "reports/demo.mp4 should not be empty");
+
+const probe = spawnSync(process.env.FFPROBE_PATH || "ffprobe", [
+ "-v",
+ "error",
+ "-select_streams",
+ "v:0",
+ "-show_entries",
+ "stream=codec_name,width,height,r_frame_rate:format=duration",
+ "-of",
+ "json",
+ videoPath
+], { encoding: "utf8" });
+
+if (probe.status !== 0) {
+ process.stderr.write(probe.stderr || "ffprobe failed\n");
+ process.exit(probe.status || 1);
+}
+
+const metadata = JSON.parse(probe.stdout);
+const stream = metadata.streams && metadata.streams[0];
+assert.equal(stream.codec_name, "h264");
+assert.equal(stream.width, 960);
+assert.equal(stream.height, 540);
+assert.equal(stream.r_frame_rate, "18/1");
+
+const duration = Number(metadata.format && metadata.format.duration);
+assert.ok(duration >= 3.9 && duration <= 4.2, `unexpected duration ${duration}`);
+
+console.log(`demo.mp4 verified: ${stream.codec_name}, ${stream.width}x${stream.height}, ${duration.toFixed(3)}s, ${stream.r_frame_rate}`);