@@ -362,6 +362,12 @@ function startAdmissionReads(params: {
362362 }
363363}
364364
365+ /** A gate refusal's warning, emitted alongside its error row so both share the throttle window. */
366+ interface GateWarning {
367+ message : string
368+ fields : Record < string , unknown >
369+ }
370+
365371export async function preprocessExecution (
366372 options : PreprocessExecutionOptions
367373) : Promise < PreprocessExecutionResult > {
@@ -401,11 +407,15 @@ export async function preprocessExecution(
401407 const isFailureLogSuppressed = ( failure : PreprocessExecutionError ) : boolean =>
402408 suppressRetryableFailureLogs && failure . statusCode >= 500 && failure . retryable === true
403409
404- /** Records an admission gate's error row, at most once per gate and outcome per window when throttled. */
410+ /**
411+ * Records an admission gate's warning and error row, at most once per gate and outcome per window
412+ * when throttled, so a sender redelivering into a refusal does not log every attempt.
413+ */
405414 const recordGateFailure = async (
406415 gate : 'ban' | 'usage' | 'rate-limit' | 'reservation' ,
407416 failure : PreprocessExecutionError ,
408- record : Parameters < typeof logPreprocessingError > [ 0 ]
417+ record : Parameters < typeof logPreprocessingError > [ 0 ] ,
418+ warning ?: GateWarning
409419 ) : Promise < void > => {
410420 if ( isFailureLogSuppressed ( failure ) ) return
411421 if (
@@ -416,10 +426,12 @@ export async function preprocessExecution(
416426 ) {
417427 return
418428 }
429+ if ( warning )
430+ logger . warn ( warning . message , { requestId, workflowId, triggerType, ...warning . fields } )
419431 await recordPreprocessingError ( record )
420432 }
421433
422- logger . info ( `[${ requestId } ] Starting execution preprocessing` , {
434+ logger . debug ( `[${ requestId } ] Starting execution preprocessing` , {
423435 workflowId,
424436 userId,
425437 triggerType,
@@ -577,21 +589,21 @@ export async function preprocessExecution(
577589 }
578590 actorUserId = validatedAttribution . actorUserId
579591 billingAttribution = validatedAttribution
580- logger . info ( `[${ requestId } ] Reusing serialized billing attribution` , {
592+ logger . debug ( `[${ requestId } ] Reusing serialized billing attribution` , {
581593 actorUserId,
582594 billingEntity : billingAttribution . billingEntity ,
583595 } )
584596 }
585597
586598 if ( ! actorUserId && useAuthenticatedUserAsActor && userId ) {
587599 actorUserId = userId
588- logger . info ( `[${ requestId } ] Using authenticated user as actor: ${ actorUserId } ` )
600+ logger . debug ( `[${ requestId } ] Using authenticated user as actor: ${ actorUserId } ` )
589601 }
590602
591603 if ( ! actorUserId ) {
592604 billingAttribution = await admission . attributionFor ( workspaceId )
593605 actorUserId = billingAttribution . actorUserId
594- logger . info ( `[${ requestId } ] Using atomically resolved system actor and payer` , {
606+ logger . debug ( `[${ requestId } ] Using atomically resolved system actor and payer` , {
595607 actorUserId,
596608 billingEntity : billingAttribution . billingEntity ,
597609 } )
@@ -672,6 +684,7 @@ export async function preprocessExecution(
672684 interface GateFailure {
673685 response : PreprocessExecutionFailure
674686 recordError ?: Parameters < typeof recordPreprocessingError > [ 0 ]
687+ warning ?: GateWarning
675688 }
676689
677690 /** Usage figures captured by the read gate and reused by the atomic reservation. */
@@ -690,13 +703,8 @@ export async function preprocessExecution(
690703 try {
691704 const bannedUserIds = await gateReads . bannedUserIds
692705 if ( bannedUserIds . length > 0 ) {
693- logger . warn ( `[${ requestId } ] Execution blocked: banned account` , {
694- workflowId,
695- bannedUserIds,
696- triggerType,
697- } )
698-
699706 return {
707+ warning : { message : 'Execution blocked: banned account' , fields : { bannedUserIds } } ,
700708 response : {
701709 success : false ,
702710 error : {
@@ -774,16 +782,17 @@ export async function preprocessExecution(
774782 }
775783 : null
776784 if ( usageCheck . isExceeded ) {
777- logger . warn ( `[${ requestId } ] Attributed usage gate blocked actor ${ actorUserId } .` , {
778- currentUsage : snapshot ?. currentUsage ,
779- limit : snapshot ?. limit ,
780- scope : usageCheck . scope ,
781- workflowId,
782- triggerType,
783- } )
784-
785785 return {
786786 failure : {
787+ warning : {
788+ message : 'Attributed usage gate blocked actor' ,
789+ fields : {
790+ actorUserId,
791+ currentUsage : snapshot ?. currentUsage ,
792+ limit : snapshot ?. limit ,
793+ scope : usageCheck . scope ,
794+ } ,
795+ } ,
787796 response : {
788797 success : false ,
789798 error : {
@@ -876,13 +885,11 @@ export async function preprocessExecution(
876885 )
877886
878887 if ( ! info . allowed ) {
879- logger . warn ( `[${ requestId } ] Rate limit exceeded for user ${ actorUserId } ` , {
880- triggerType,
881- remaining : info . remaining ,
882- resetAt : info . resetAt ,
883- } )
884-
885888 return {
889+ warning : {
890+ message : 'Rate limit exceeded' ,
891+ fields : { actorUserId, remaining : info . remaining , resetAt : info . resetAt } ,
892+ } ,
886893 response : {
887894 success : false ,
888895 error : {
@@ -947,7 +954,8 @@ export async function preprocessExecution(
947954 await recordGateFailure (
948955 banFailure ? 'ban' : 'usage' ,
949956 readGateFailure . response . error ,
950- readGateFailure . recordError
957+ readGateFailure . recordError ,
958+ readGateFailure . warning
951959 )
952960 }
953961 return readGateFailure . response
@@ -959,7 +967,8 @@ export async function preprocessExecution(
959967 await recordGateFailure (
960968 'rate-limit' ,
961969 rateLimitFailure . response . error ,
962- rateLimitFailure . recordError
970+ rateLimitFailure . recordError ,
971+ rateLimitFailure . warning
963972 )
964973 }
965974 return rateLimitFailure . response
@@ -1009,12 +1018,6 @@ export async function preprocessExecution(
10091018 reservation . reason
10101019 )
10111020 const message = RESERVATION_DENIAL_MESSAGE [ reservation . reason ]
1012- logger . warn ( `[${ requestId } ] Admission reservation full for user ${ actorUserId } ` , {
1013- workflowId,
1014- triggerType,
1015- constraint : reservation . reason ,
1016- } )
1017-
10181021 const failure : PreprocessExecutionError = {
10191022 message,
10201023 statusCode : descriptor . statusCode ,
@@ -1026,17 +1029,25 @@ export async function preprocessExecution(
10261029 constraint : reservation . reason ,
10271030 } ,
10281031 }
1029- await recordGateFailure ( 'reservation' , failure , {
1030- workflowId,
1031- executionId,
1032- triggerType,
1033- requestId,
1034- userId : actorUserId ,
1035- workspaceId,
1036- errorMessage : message ,
1037- loggingSession : providedLoggingSession ,
1038- triggerData,
1039- } )
1032+ await recordGateFailure (
1033+ 'reservation' ,
1034+ failure ,
1035+ {
1036+ workflowId,
1037+ executionId,
1038+ triggerType,
1039+ requestId,
1040+ userId : actorUserId ,
1041+ workspaceId,
1042+ errorMessage : message ,
1043+ loggingSession : providedLoggingSession ,
1044+ triggerData,
1045+ } ,
1046+ {
1047+ message : 'Admission reservation full' ,
1048+ fields : { actorUserId, constraint : reservation . reason } ,
1049+ }
1050+ )
10401051
10411052 return { success : false , error : failure }
10421053 }
@@ -1068,7 +1079,7 @@ export async function preprocessExecution(
10681079 }
10691080 }
10701081
1071- logger . info ( `[${ requestId } ] All preprocessing checks passed` , {
1082+ logger . debug ( `[${ requestId } ] All preprocessing checks passed` , {
10721083 workflowId,
10731084 actorUserId,
10741085 triggerType,
0 commit comments