修复循环信号与事件采样并接入 LSTP 接触定位,补充八路验证及复用实验
相较上一版 Jacobian 确定性复用更新,本次补齐事件边界一致性、结果两侧采样及接触事件定位;保留已有物性复用和组件力学公式。 - 统一 UD00 信号求值与下一事件查询的绝对时间边界,修复循环边界浮点舍入导致的阶段错位、重复或漏报,并覆盖零时长、多阶段及长周期场景。 - 引入原生输出语义 v2:保留规则网格真实时间,补充内部时间事件和状态事件的左邻及事件后采样,按保存时间、状态和离散模式重放结果。 - 两条代码生成路径均发出 LSTP 接触描述,默认定位间隙过零及非负力模式的力截断;仅在接受事件时更新防重复记录,增加 contactEvents 诊断计数。 - 补充 MASS/LSTP 独立事件实验、八路全曲线与驱动阶段配对评估,以及 Amesim 不连续点输出对照和力差定位报告;MASS 新增释放机制仍保留为独立实验。 - 保存局部 probe、context 访问与回退、shadow replay、R288 real skip/typed replay 及阀门数值尾部诊断工具和报告;未证明净收益的实验不启用为生产默认优化。 - 更新原生运行说明和元件建模规范,补充信号边界、输出语义、接触事件和实验依赖回归测试。 验证:五组专项回归共 34 项全部通过;37 个待提交 Python 文件语法检查通过;git diff --cached --check 通过。
This commit is contained in:
1 parent
1aac220084
commit
7611f13208
85 files changed
+11358
-33
No files matched your search
@@ -0,0 +1,213 @@
|
||||
/* Included after the unchanged local_probe_support.c, so baseline snapshots
|
||||
are observed directly. None of the original guard or restore code is edited. */
|
||||
#include "context_fallback_diag.h"
|
||||
#include <stddef.h>
|
||||
/* DIAG_TABLES */
|
||||
int dx_mode,dx_selected,dx_region=-1,dx_position=-1,dx_shadow;
|
||||
static uint64_t dx_jac,dx_sampled,dx_tick0,dx_q0,dx_region_tick,dx_op_tick;
|
||||
static unsigned dx_stride=16,dx_seed=1,dx_pick;
|
||||
static double dx_time;
|
||||
typedef struct {
|
||||
uint64_t attempts,compares,failures,region_ticks,op_ticks,ops;
|
||||
uint64_t input_diff_ops,output_diff_ops,exit_output_diff,exit_context_diff;
|
||||
} DxRegion;
|
||||
static DxRegion dx_stats[LP_NC][LP_NR];
|
||||
static uint64_t dx_op_count[LP_NC][LP_NO],dx_op_ticks[LP_NC][LP_NO];
|
||||
static uint64_t dx_kernel_count[LP_NR][DX_NK],dx_kernel_inclusive[LP_NR][DX_NK],dx_kernel_exclusive[LP_NR][DX_NK];
|
||||
static double dx_inputs[DX_NIN],dx_outputs[DX_NOUT];
|
||||
static FILE *dx_fail_file,*dx_matrix_file;
|
||||
static FILE *dx_input_file;
|
||||
static FILE *dx_create_file;
|
||||
static int dx_trace,dx_details,dx_first_context=-999,dx_seen[LP_NB],dx_source[LP_NB];
|
||||
static Snapshot dx_history[LP_NB];
|
||||
static struct {uint64_t start,child;int kind,region;} dx_stack[64];
|
||||
static int dx_depth;
|
||||
typedef struct {const char *name;size_t offset,size;int floating;} DxField;
|
||||
#define DX_FIELD(type,field,float_flag) {#field,offsetof(type,field),sizeof(((type*)0)->field),float_flag}
|
||||
#define DX_MEDIUM(type,field,float_flag) {"medium." #field,offsetof(type,medium)+offsetof(NativeMedium,field),sizeof(((NativeMedium*)0)->field),float_flag}
|
||||
#define DX_MEDIUM_FIELDS(type) DX_MEDIUM(type,real_helium,0),DX_MEDIUM(type,R,1),DX_MEDIUM(type,cp,1),DX_MEDIUM(type,Tref,1),DX_MEDIUM(type,slope,1),DX_MEDIUM(type,mu,1),DX_MEDIUM(type,muT,1),DX_MEDIUM(type,S,1)
|
||||
static const DxField dx_state_fields[]={DX_MEDIUM_FIELDS(NativePropertyState),
|
||||
DX_FIELD(NativePropertyState,p,1),DX_FIELD(NativePropertyState,T,1),DX_FIELD(NativePropertyState,h,1),
|
||||
DX_FIELD(NativePropertyState,rho,1),DX_FIELD(NativePropertyState,mu,1),DX_FIELD(NativePropertyState,isentropic_factor,1),
|
||||
DX_FIELD(NativePropertyState,isentropic_exponent,1),DX_FIELD(NativePropertyState,valid,0),
|
||||
DX_FIELD(NativePropertyState,temperatures,0),DX_FIELD(NativePropertyState,jacobian,0)};
|
||||
static const DxField dx_pipe_fields[]={DX_MEDIUM_FIELDS(NativePipeCache),
|
||||
DX_FIELD(NativePipeCache,p1,1),DX_FIELD(NativePipeCache,p2,1),DX_FIELD(NativePipeCache,T,1),
|
||||
DX_FIELD(NativePipeCache,diameter,1),DX_FIELD(NativePipeCache,length,1),DX_FIELD(NativePipeCache,roughness,1),
|
||||
DX_FIELD(NativePipeCache,flow,1),DX_FIELD(NativePipeCache,kind,0),DX_FIELD(NativePipeCache,valid,0)};
|
||||
typedef struct {int kind,index,field;size_t offset,size;uint64_t baseline,trial;} DxDifference;
|
||||
static DxDifference dx_difference(NativePropertyCache*,NativePipeCache*,Snapshot*);
|
||||
static void dx_boundary(int pos,int source,NativePropertyCache *p,NativePipeCache *pipes){
|
||||
if(!dx_trace || lp_color<0)return;
|
||||
int v=dx_version[pos];if(dx_seen[v])return;
|
||||
Snapshot *s=&dx_history[v];memset(s,0,sizeof(*s));
|
||||
s->count=p->count;s->capacity=p->capacity;s->temperatures=p->temperatures;s->jacobian=p->jacobian;
|
||||
memcpy(s->states,p->states,p->count*sizeof(*p->states));memcpy(s->pipes,pipes,sizeof(s->pipes));
|
||||
dx_seen[v]=1;dx_source[v]=source;
|
||||
if(dx_first_context==-999 && dx_difference(p,pipes,&saved->snapshots[v]).kind)dx_first_context=source;
|
||||
}
|
||||
static int dx_field_equal(Snapshot *a,Snapshot *b,DxDifference d){
|
||||
if(d.kind==1){uint64_t x[]={a->count,a->capacity,(uintptr_t)a->temperatures,(uintptr_t)a->jacobian};uint64_t y[]={b->count,b->capacity,(uintptr_t)b->temperatures,(uintptr_t)b->jacobian};return x[d.field]==y[d.field];}
|
||||
if(d.kind==2 && ((size_t)d.index>=a->count || (size_t)d.index>=b->count))return (size_t)d.index>=a->count && (size_t)d.index>=b->count;
|
||||
unsigned char *x=(unsigned char*)(d.kind==2?(void*)&a->states[d.index]:(void*)&a->pipes[d.index]);
|
||||
unsigned char *y=(unsigned char*)(d.kind==2?(void*)&b->states[d.index]:(void*)&b->pipes[d.index]);
|
||||
return memcmp(x+d.offset,y+d.offset,d.size)==0;
|
||||
}
|
||||
static int dx_origin(DxDifference d,int v,int *first){
|
||||
int previous_equal=1,origin=-999;*first=-999;
|
||||
for(int i=0;i<=v;i++)if(dx_seen[i]){
|
||||
int equal=dx_field_equal(&dx_history[i],&saved->snapshots[i],d);
|
||||
if(!equal && previous_equal){origin=dx_source[i];if(*first==-999)*first=origin;}
|
||||
previous_equal=equal;
|
||||
}
|
||||
return origin;
|
||||
}
|
||||
static DxDifference dx_difference(NativePropertyCache *p,NativePipeCache *pipes,Snapshot *b){
|
||||
DxDifference d={0,-1,-1,0,0,0,0};
|
||||
uint64_t bm[]={b->count,b->capacity,(uintptr_t)b->temperatures,(uintptr_t)b->jacobian};
|
||||
uint64_t pm[]={p->count,p->capacity,(uintptr_t)p->temperatures,(uintptr_t)p->jacobian};
|
||||
for(int i=0;i<4;i++)if(bm[i]!=pm[i]){d.kind=1;d.field=i;d.baseline=bm[i];d.trial=pm[i];return d;}
|
||||
for(int kind=2;kind<=3;kind++){
|
||||
size_t size=kind==2?sizeof(NativePropertyState):sizeof(NativePipeCache),count=kind==2?b->count:LP_NPC;
|
||||
const unsigned char *a=(const unsigned char*)(kind==2?(void*)b->states:(void*)b->pipes),*c=(const unsigned char*)(kind==2?(void*)p->states:(void*)pipes);
|
||||
const DxField *fields=kind==2?dx_state_fields:dx_pipe_fields;
|
||||
int nf=kind==2?(int)(sizeof(dx_state_fields)/sizeof(*dx_state_fields)):(int)(sizeof(dx_pipe_fields)/sizeof(*dx_pipe_fields));
|
||||
for(size_t i=0;i<count*size;i++)if(a[i]!=c[i]){
|
||||
d.kind=kind;d.index=(int)(i/size);size_t off=i%size;d.offset=off;d.size=1;
|
||||
for(int f=0;f<nf;f++)if(off>=fields[f].offset && off<fields[f].offset+fields[f].size){d.field=f;d.offset=fields[f].offset;d.size=fields[f].size;break;}
|
||||
memcpy(&d.baseline,a+d.index*size+d.offset,d.size);memcpy(&d.trial,c+d.index*size+d.offset,d.size);return d;
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
static void dx_failure(int r,NativePropertyCache *p,NativePipeCache *pipes){
|
||||
if(dx_mode==5 && !dx_trace)return;
|
||||
DxDifference d=dx_difference(p,pipes,&saved->snapshots[lp_before[r]]);
|
||||
if(!d.kind){fprintf(stderr,"failure without difference\n");abort();}
|
||||
int first=-999,origin=dx_trace?dx_origin(d,dx_version[dx_start_pos[r]],&first):-999;
|
||||
fprintf(dx_fail_file,"{\"jac\":%llu,\"t\":%.17g,\"group\":%d,\"region\":%d,\"kind\":%d,\"index\":%d,\"field\":%d,\"offset\":%llu,\"baseline\":\"%016llx\",\"trial\":\"%016llx\",\"firstOrigin\":%d,\"persistentOrigin\":%d,\"firstContextOrigin\":%d}\n",
|
||||
(unsigned long long)(dx_jac-1),dx_time,lp_color,r,d.kind,d.index,d.field,(unsigned long long)d.offset,(unsigned long long)d.baseline,(unsigned long long)d.trial,first,origin,dx_first_context);
|
||||
}
|
||||
void dx_initialize(void){
|
||||
const char *m=getenv("CONTEXT_DIAG_MODE"),*s=getenv("CONTEXT_DIAG_STRIDE"),*seed=getenv("CONTEXT_DIAG_SEED"),*mat=getenv("CONTEXT_DIAG_MATRICES");
|
||||
dx_mode=m?atoi(m):1;dx_stride=s?(unsigned)atoi(s):16;dx_seed=seed?(unsigned)atoi(seed):1;
|
||||
dx_q0=lp_tick();dx_tick0=dx_clock();
|
||||
if(dx_mode==1 || dx_mode==5){dx_fail_file=fopen("failures.jsonl","wb");if(!dx_fail_file)abort();setvbuf(dx_fail_file,NULL,_IOFBF,1024*1024);}
|
||||
if(dx_mode==5){dx_input_file=fopen("trace-inputs.jsonl","wb");if(!dx_input_file)abort();}
|
||||
if(dx_mode==5){dx_create_file=fopen("trace-created.jsonl","wb");if(!dx_create_file)abort();}
|
||||
if(mat && atoi(mat)){dx_matrix_file=fopen("jacobians.bin","wb");if(!dx_matrix_file)abort();setvbuf(dx_matrix_file,NULL,_IOFBF,1024*1024);}
|
||||
}
|
||||
void dx_jacobian(void){
|
||||
unsigned pos=(unsigned)(dx_jac++%(dx_stride?dx_stride:1));
|
||||
if(!pos){dx_seed^=dx_seed<<13;dx_seed^=dx_seed>>17;dx_seed^=dx_seed<<5;dx_pick=dx_seed%(dx_stride?dx_stride:1);}
|
||||
dx_selected=dx_mode==1 || dx_mode==5 || (dx_stride && pos==dx_pick);
|
||||
dx_trace=dx_mode==5;
|
||||
dx_details=dx_mode==5 && (dx_jac==1 || dx_jac==201 || dx_jac==451 || dx_jac==701 || dx_jac==896);
|
||||
if(dx_selected)dx_sampled++;
|
||||
}
|
||||
void dx_eval_begin(double t,const double *y){(void)y;dx_time=t;dx_region=-1;dx_position=-1;dx_first_context=-999;memset(dx_seen,0,sizeof(dx_seen));}
|
||||
void dx_eval_end(void){if(dx_region>=0){fprintf(stderr,"unclosed fallback region\n");abort();}dx_position=-1;}
|
||||
void dx_schedule(NativePropertyCache *p,NativePipeCache *pipes){dx_region=-1;dx_boundary(0,-2,p,pipes);}
|
||||
int dx_reuse(int r,NativePropertyCache *p,NativePipeCache *pipes,double *pv,double *h,double *q,double *w,double *fb){
|
||||
int ok=lp_reuse(r,p,pipes,pv,h,q,w,fb);
|
||||
DxRegion *s=&dx_stats[lp_color][r];s->attempts++;if(dx_contextual[r])s->compares++;
|
||||
if(!ok){
|
||||
if(!dx_contextual[r])abort();
|
||||
s->failures++;dx_region=r;
|
||||
if(dx_fail_file)dx_failure(r,p,pipes);
|
||||
if(dx_mode>=2 && dx_mode<=4)dx_region_tick=dx_clock();
|
||||
}
|
||||
else dx_boundary(lp_end[r],-1000-r,p,pipes);
|
||||
return ok;
|
||||
}
|
||||
void dx_op_begin(int pos,const double *inputs){
|
||||
dx_position=pos;
|
||||
if(lp_color<0){if(dx_mode==1 || dx_mode==5)memcpy(dx_inputs+dx_in_offset[pos],inputs,(dx_in_offset[pos+1]-dx_in_offset[pos])*sizeof(double));return;}
|
||||
if(dx_details){
|
||||
int any=0;
|
||||
for(int i=0;i<dx_in_offset[pos+1]-dx_in_offset[pos];i++)if(memcmp(&inputs[i],&dx_inputs[dx_in_offset[pos]+i],8)){
|
||||
uint64_t a,b;memcpy(&a,&dx_inputs[dx_in_offset[pos]+i],8);memcpy(&b,&inputs[i],8);
|
||||
if(!any)fprintf(dx_input_file,"{\"jac\":%llu,\"group\":%d,\"position\":%d,\"inputs\":[",(unsigned long long)(dx_jac-1),lp_color,pos);
|
||||
fprintf(dx_input_file,"%s[%d,\"%016llx\",\"%016llx\"]",any++?",":"",i,(unsigned long long)a,(unsigned long long)b);
|
||||
}
|
||||
if(any)fprintf(dx_input_file,"]}\n");
|
||||
}
|
||||
if(dx_region<0)return;
|
||||
dx_stats[lp_color][dx_region].ops++;dx_op_count[lp_color][pos]++;
|
||||
if(dx_mode==1 || dx_mode==5){
|
||||
if(memcmp(dx_inputs+dx_in_offset[pos],inputs,(dx_in_offset[pos+1]-dx_in_offset[pos])*sizeof(double)))dx_stats[lp_color][dx_region].input_diff_ops++;
|
||||
}
|
||||
if(dx_mode==3 || dx_mode==4)dx_op_tick=dx_clock();
|
||||
}
|
||||
void dx_op_end(int pos,const double *outputs,NativePropertyCache *p,NativePipeCache *pipes){
|
||||
if(dx_mutates[pos])dx_boundary(pos+1,pos,p,pipes);
|
||||
if(lp_color<0){if(dx_mode==1 || dx_mode==5)memcpy(dx_outputs+dx_out_offset[pos],outputs,(dx_out_offset[pos+1]-dx_out_offset[pos])*sizeof(double));return;}
|
||||
if(dx_region<0)return;
|
||||
if(dx_mode==3 || dx_mode==4){uint64_t elapsed=dx_clock()-dx_op_tick;dx_op_ticks[lp_color][pos]+=elapsed;dx_stats[lp_color][dx_region].op_ticks+=elapsed;}
|
||||
if((dx_mode==1 || dx_mode==5) && memcmp(dx_outputs+dx_out_offset[pos],outputs,(dx_out_offset[pos+1]-dx_out_offset[pos])*sizeof(double)))dx_stats[lp_color][dx_region].output_diff_ops++;
|
||||
}
|
||||
void dx_region_end(double *p,double *h,double *q,double *w,double *fb,NativePropertyCache *properties,NativePipeCache *pipes){
|
||||
if(dx_region<0)return;
|
||||
int r=dx_region;
|
||||
if(dx_mode>=2 && dx_mode<=4)dx_stats[lp_color][r].region_ticks+=dx_clock()-dx_region_tick;
|
||||
if(dx_mode==1 || dx_mode==5){
|
||||
double *dst[]={p,h,q,w,fb};double *src[]={saved->p,saved->h,saved->q,saved->w,saved->fb};int changed=0;
|
||||
for(int i=lp_first_output[r];i<lp_last_output[r];i++)changed|=memcmp(&dst[lp_output_map[i][0]][lp_output_map[i][1]],&src[lp_output_map[i][0]][lp_output_map[i][1]],sizeof(double))!=0;
|
||||
dx_stats[lp_color][r].exit_output_diff+=changed;
|
||||
dx_stats[lp_color][r].exit_context_diff+=dx_difference(properties,pipes,&saved->snapshots[lp_after[r]]).kind!=0;
|
||||
}
|
||||
dx_region=-1;
|
||||
}
|
||||
uint64_t dx_kernel_begin(int kind){
|
||||
if(dx_mode==5 && dx_details && !dx_shadow && dx_position>=0){
|
||||
if(dx_region>=0 && lp_color>=0)dx_kernel_count[dx_region][kind]++;
|
||||
if(dx_depth>=64)abort();
|
||||
dx_stack[dx_depth].kind=kind;dx_depth++;return 1;
|
||||
}
|
||||
if(!dx_selected || dx_shadow || dx_region<0 || lp_color<0)return 0;
|
||||
dx_kernel_count[dx_region][kind]++;
|
||||
if(dx_mode!=4)return 0;
|
||||
if(dx_depth>=64)abort();
|
||||
uint64_t t=dx_clock();dx_stack[dx_depth].start=t;dx_stack[dx_depth].child=0;dx_stack[dx_depth].kind=kind;dx_stack[dx_depth].region=dx_region;dx_depth++;return t;
|
||||
}
|
||||
void dx_kernel_end(int kind,uint64_t start){
|
||||
if(!start)return;
|
||||
if(start==1 && dx_mode==5){if(--dx_depth<0 || dx_stack[dx_depth].kind!=kind)abort();return;}
|
||||
uint64_t elapsed=dx_clock()-start;int i=--dx_depth;
|
||||
if(i<0 || dx_stack[i].kind!=kind)abort();
|
||||
int r=dx_stack[i].region;dx_kernel_inclusive[r][kind]+=elapsed;dx_kernel_exclusive[r][kind]+=elapsed-dx_stack[i].child;
|
||||
if(i)dx_stack[i-1].child+=elapsed;
|
||||
}
|
||||
void dx_property_created(NativePropertyCache *p,NativePropertyState *s){
|
||||
if(!dx_details || dx_position<0 || !p)return;
|
||||
uintptr_t a=(uintptr_t)s,b=(uintptr_t)p->states;
|
||||
int slot=a>=b && a<b+p->capacity*sizeof(*s)?(int)((a-b)/sizeof(*s)):-1;
|
||||
fprintf(dx_create_file,"{\"jac\":%llu,\"group\":%d,\"position\":%d,\"slot\":%d,\"p\":%.17g,\"T\":%.17g,\"count\":%llu,\"path\":[",(unsigned long long)(dx_jac-1),lp_color,dx_position,slot,s->p,s->T,(unsigned long long)p->count);
|
||||
for(int i=0;i<dx_depth;i++)fprintf(dx_create_file,"%s%d",i?",":"",dx_stack[i].kind);
|
||||
fprintf(dx_create_file,"]}\n");
|
||||
}
|
||||
void dx_validate_matrix(double t,const double *y,const double *m){if(dx_matrix_file){fwrite(&t,8,1,dx_matrix_file);fwrite(y,8,NSTATES,dx_matrix_file);fwrite(m,8,NSTATES*NSTATES,dx_matrix_file);}}
|
||||
void dx_finish(void){
|
||||
double hz=(double)(dx_clock()-dx_tick0)/((double)(lp_tick()-dx_q0)/frequency);
|
||||
if(dx_fail_file)fclose(dx_fail_file);
|
||||
if(dx_matrix_file)fclose(dx_matrix_file);
|
||||
if(dx_input_file)fclose(dx_input_file);
|
||||
if(dx_create_file)fclose(dx_create_file);
|
||||
FILE *f=fopen("context.json","wb");if(!f)abort();
|
||||
fprintf(f,"{\"mode\":%d,\"frequency\":%.9f,\"jacobians\":%llu,\"sampled\":%llu,\"regions\":[",dx_mode,hz,(unsigned long long)dx_jac,(unsigned long long)dx_sampled);
|
||||
int comma=0;
|
||||
for(int g=0;g<LP_NC;g++)for(int r=0;r<LP_NR;r++){
|
||||
DxRegion *s=&dx_stats[g][r];if(!s->attempts)continue;
|
||||
fprintf(f,"%s{\"group\":%d,\"region\":%d,\"attempts\":%llu,\"compares\":%llu,\"failures\":%llu,\"regionTicks\":%llu,\"opTicks\":%llu,\"ops\":%llu,\"inputDiffOps\":%llu,\"outputDiffOps\":%llu,\"exitOutputDiff\":%llu,\"exitContextDiff\":%llu}",comma++?",":"",g,r,(unsigned long long)s->attempts,(unsigned long long)s->compares,(unsigned long long)s->failures,(unsigned long long)s->region_ticks,(unsigned long long)s->op_ticks,(unsigned long long)s->ops,(unsigned long long)s->input_diff_ops,(unsigned long long)s->output_diff_ops,(unsigned long long)s->exit_output_diff,(unsigned long long)s->exit_context_diff);
|
||||
}
|
||||
fprintf(f,"],\"operations\":[");comma=0;
|
||||
for(int g=0;g<LP_NC;g++)for(int p=0;p<LP_NO;p++)if(dx_op_count[g][p])fprintf(f,"%s[%d,%d,%llu,%llu]",comma++?",":"",g,p,(unsigned long long)dx_op_count[g][p],(unsigned long long)dx_op_ticks[g][p]);
|
||||
fprintf(f,"],\"kernels\":[");comma=0;
|
||||
for(int r=0;r<LP_NR;r++)for(int k=0;k<DX_NK;k++)if(dx_kernel_count[r][k])fprintf(f,"%s[%d,%d,%llu,%llu,%llu]",comma++?",":"",r,k,(unsigned long long)dx_kernel_count[r][k],(unsigned long long)dx_kernel_inclusive[r][k],(unsigned long long)dx_kernel_exclusive[r][k]);
|
||||
fprintf(f,"],\"fields\":{");
|
||||
for(int kind=2;kind<=3;kind++){
|
||||
const DxField *fields=kind==2?dx_state_fields:dx_pipe_fields;int n=kind==2?(int)(sizeof(dx_state_fields)/sizeof(*dx_state_fields)):(int)(sizeof(dx_pipe_fields)/sizeof(*dx_pipe_fields));
|
||||
fprintf(f,"%s\"%d\":[",kind==2?"":",",kind);for(int i=0;i<n;i++)fprintf(f,"%s{\"name\":\"%s\",\"offset\":%llu,\"size\":%llu,\"floating\":%d}",i?",":"",fields[i].name,(unsigned long long)fields[i].offset,(unsigned long long)fields[i].size,fields[i].floating);fprintf(f,"]");
|
||||
}
|
||||
fprintf(f,"}}\n");fclose(f);
|
||||
}
|
||||
Reference in new issue
Block a user