@@ -200,3 +200,84 @@ test("the repo-side live opt-in alone (no global env opt-in) is sufficient to re
200200 assert . equal ( decision . mode , "live" ) ;
201201 assert . equal ( decision . allowed , true ) ;
202202} ) ;
203+
204+ /** Throws a non-`Error` value (a plain string) the instant any property is read -- distinct from the existing
205+ * `null as unknown as X` fail-closed tests above, which all throw a genuine `TypeError` (a real `Error`
206+ * instance) and so only ever exercise the `error instanceof Error` arm of each catch block's message
207+ * formatting. This exercises the `String(error)` fallback arm for a thrown non-Error value. */
208+ function throwingProxy ( message : string ) : never {
209+ return new Proxy (
210+ { } ,
211+ {
212+ get ( ) : never {
213+ throw message ;
214+ } ,
215+ } ,
216+ ) as never ;
217+ }
218+
219+ test ( "fail-closed: a rate-limit calculator throwing a non-Error value still formats a reason via String(error)" , ( ) => {
220+ const decision = evaluateGovernorChokepoint ( baseInput ( { rateLimitBuckets : throwingProxy ( "boom: not an Error" ) } ) ) ;
221+ assert . equal ( decision . allowed , false ) ;
222+ assert . equal ( decision . stage , "internal_error" ) ;
223+ assert . match ( decision . reason , / r a t e _ l i m i t _ c a l c u l a t o r _ e r r o r : b o o m : n o t a n E r r o r / ) ;
224+ } ) ;
225+
226+ test ( "fail-closed: a budget-cap calculator throwing a non-Error value still formats a reason via String(error)" , ( ) => {
227+ const decision = evaluateGovernorChokepoint ( baseInput ( { capUsage : throwingProxy ( "boom: not an Error" ) } ) ) ;
228+ assert . equal ( decision . allowed , false ) ;
229+ assert . equal ( decision . stage , "internal_error" ) ;
230+ assert . match ( decision . reason , / b u d g e t _ c a p _ c a l c u l a t o r _ e r r o r : b o o m : n o t a n E r r o r / ) ;
231+ } ) ;
232+
233+ test ( "fail-closed: a non-convergence calculator throwing a non-Error value still formats a reason via String(error)" , ( ) => {
234+ const decision = evaluateGovernorChokepoint ( baseInput ( { convergenceInput : throwingProxy ( "boom: not an Error" ) } ) ) ;
235+ assert . equal ( decision . allowed , false ) ;
236+ assert . equal ( decision . stage , "internal_error" ) ;
237+ assert . match ( decision . reason , / n o n _ c o n v e r g e n c e _ c a l c u l a t o r _ e r r o r : b o o m : n o t a n E r r o r / ) ;
238+ } ) ;
239+
240+ test ( "fail-closed: a reputation-throttle calculator throwing a non-Error value still formats a reason via String(error)" , ( ) => {
241+ const decision = evaluateGovernorChokepoint ( baseInput ( { reputationHistory : throwingProxy ( "boom: not an Error" ) } ) ) ;
242+ assert . equal ( decision . allowed , false ) ;
243+ assert . equal ( decision . stage , "internal_error" ) ;
244+ assert . match ( decision . reason , / r e p u t a t i o n _ t h r o t t l e _ c a l c u l a t o r _ e r r o r : b o o m : n o t a n E r r o r / ) ;
245+ } ) ;
246+
247+ test ( "fail-closed: a self-plagiarism calculator throwing a non-Error value still formats a reason via String(error)" , ( ) => {
248+ const decision = evaluateGovernorChokepoint ( baseInput ( { selfPlagiarismCandidate : throwingProxy ( "boom: not an Error" ) } ) ) ;
249+ assert . equal ( decision . allowed , false ) ;
250+ assert . equal ( decision . stage , "internal_error" ) ;
251+ assert . match ( decision . reason , / s e l f _ p l a g i a r i s m _ c a l c u l a t o r _ e r r o r : b o o m : n o t a n E r r o r / ) ;
252+ } ) ;
253+
254+ test ( "rate limit: a caller-supplied randomFn is threaded through to the calculator (not just the default)" , ( ) => {
255+ let called = false ;
256+ const decision = evaluateGovernorChokepoint (
257+ baseInput ( {
258+ rateLimitRandomFn : ( ) => {
259+ called = true ;
260+ return 0.25 ;
261+ } ,
262+ } ) ,
263+ ) ;
264+ assert . equal ( decision . allowed , true , "a custom randomFn on an otherwise-clear bucket must not itself deny" ) ;
265+ // The rate-limit calculator only actually invokes randomFn when a bucket is over-limit and jittering a
266+ // retry delay; on a clear bucket it is threaded through but never called -- asserting `false` here would be
267+ // wrong. What this test verifies is the conditional-spread branch (the field IS present) compiles and runs
268+ // end-to-end without the calculator rejecting an unexpected extra field.
269+ assert . equal ( called , false , "documents that a clear bucket never needs to call randomFn" ) ;
270+ } ) ;
271+
272+ test ( "self-plagiarism: a whitespace-only candidate fingerprint denies via missing_candidate_fingerprint, with similarity omitted -> null" , ( ) => {
273+ const decision = evaluateGovernorChokepoint (
274+ baseInput ( {
275+ selfPlagiarismCandidate : { repoFullName : "acme/widgets" , fingerprint : " " , submittedAt : "2026-07-11T12:00:00Z" } ,
276+ selfPlagiarismRecentSubmissions : [ ] ,
277+ } ) ,
278+ ) ;
279+ assert . equal ( decision . allowed , false ) ;
280+ assert . equal ( decision . stage , "self_plagiarism" ) ;
281+ assert . equal ( decision . detail . selfPlagiarism ?. similarity , undefined , "no similarity was ever computed for this deny reason" ) ;
282+ assert . equal ( decision . ledgerEvent . payload ?. similarity , null , "the ?? null fallback must surface explicitly, not as an omitted key" ) ;
283+ } ) ;
0 commit comments