GN30A-eh_
ziTOvvFDUV=Cf@5OXOp_g3PhsUj@lL$#yaWDcxkW-X68auu$B(B}+1R>@bDFJuU
zRV}l=mVJR>Wp3s6&bKe`rMll#pHTh|ZymM<(vY}COjGmp3%eX7KfY*2DlbcT!
zra}DOKOLuVp#EFt&DZI&n!s(&+;-y+znBi+H_4qT3WNyQf!H2^GZ}J?y8{ps3fRU@
zgOOf26L~?#-)h($-$y{{9;uy>_0V@hsr{a7b5@i$7p{dPf9s>zQ?+58!VQ;$y2qDm
z3A4<#hCD!&9&Zb@WZjn*+rVg?_I3KA0UDAB+T9sNu5BpQaMx%OGHZcJRkG)?^jI*i
zF5`SR-p_-XE_)cDzdJVrg=*Gs=t;+7TNE?G5}vAuv3;SFdf_3YOIXL>HUWa{g0Tur
z+86|>wwu4iu*Vu}f5IR*LTkB>D`43x>Vxr(=;Xfd=E*Q^tI1S&OzHo%_2V-`nBU&D
z@03Zme&Hc&xZH=M3l((MZ8b*q@=*OUXyi=(q8$VlWMc6;y(Oyb(g5e*1~h6`jjhl{
z%VtO&xbfQcOLm%~6N&QJ7LW*HK*1Uv$QaFwwnKNvRT4$dl~FAW5+U(w3zUNv<)pD^
zDe}no{ol8!$*+p>9AI~yjYCusYFfBvID^sMBZNMz;MeO~Sy)Ze5Ve8`x*ghQ2qJka
zI#uW?P+??;ekC^=Q>u6E72ox3Y_spJygViHk9z6&MFe~JuV?$w;gK$mzhvYH>Rb?m
zkn$lJuQCYH2T0q)Y6=#}xkqo|@_!vQY(v8>Y~S4`qY&-{e!0eLgXBL$gFbnFh_v|3
zh-K8YK@i10`G(^2rz|~4fRVs(N3xmP&`u$HZQF|A9L+wT`=E!*$5^igP
zPM)nVn6`uB0$;Lvy?(aprGNNr(l0H*Y!FwQtjunq5x*G<&9}O^(5N@-p*@XF31jc1dxJw*Ow%
zsgCI2Nl5FXwO--A+L|DtEJN`V|6}pQUie`JHGYTV2=)#=NK`pf?ok}Zo=x?$KhIY}
zSLccRdrvH@GFGTml%_5Es6s)=nKXO@w{FyWsrtxWc8=ZQM}+5rRcu@CvcPNK5aRZi
zc*I)78RA0x$uth9q>A?@lQ$3FolzM2E}4@oLcU2rt9_}Gw%<@M#3Hm;%{V4ERqQs{
zGxytV1)!+@$A$@N?y_
zl1@`-M^hN4OnS8}2Q*AFH;%WNvoW38Ys6~
zMSuTbt~9D1p6s+cNtSCp^)b|E+9z*Xl|i4$#ry3cl@&A{CiAm5#NzlAm3HJzquD7l
zllxvF7!+}lFwapt?=EduKi!NRHsA758lm*K#II{k6^
zxfO9Yzy{qi50lyOmIm4A(^M$aTe-_IWg(MaRODU)?p7OEmjOS+Dz5}I?WZQ*kMRqy
z^1#ot2+0wl9$;=DqK!ip{D%KbcZ1maX{ordkAz0_B!*OPzDQ1O>({7cP%$K@59b#c
z6W8Fv$RE15^_(!*0&J74Y-oEq(~NxAjvBFE6Q9I|AiuJ&KgzLDS2e8*rQW38mQ&h!
zLR&uXw5l*n_F_!?TIY$Pm-RSKHKrv2B?`Nt#oBrCzw5}K;fcM0jB44#b+hZsMR~h5~o4;2eJ7LEQ*+@JeJ|na@
z`W|qiT1L|^B!qI8Jz=Z*TV(e)ENN}rSx--QyjI6!3_-y2Fw#VAlVtwDej*Q~&HMB&
zyV=e|)~O`;8W)eWn-V5$d~UQCVXr~>HU{50LbDkdrtD!7<&
z@(z|LDjhsU4rS8|WuGw=GG(ccLTo9X|X)+<$*k&2nAUI{tpdCa58#U15Mrg*C6{J3Qg+)>p1cwj+=p
zkN$#kII`00z~R6|$*yAE-3tAurvyb<+U;qP4jbsbTM5TKKD9TSI#ZTO-Esn+n4~~!
zNyq6Mxt|?yJ&J>rs|jI6Rb%WjFf9$W7VjQytN2esI$FCr0xR&ABX$b*GBojK3Jl0B
zg>I%t5l_3-ly<$8d}Y?D2y$aAsR~bZ9t~imoA2XirdmA|x`&i*2kNJSR(mHt
z^A&2ceY~xWdVpN?Iq9zKVDo>w%&F-(CTfOt`DLS?1-%)fQDN2g&B>=mh@DPP@>NENGPIJc;v42+*`rmqjoI&)!h{z&fm^g!EO6s6
z8$LlE#5Z{~SK2$hc<$^*WPM-_%&Qb{{(${*P^Rrg}2GG
zpmMywpHx5Pgh_-DlUHoOrh?G>cc95lY|Btx&iUZCm4|6U(FqU~{0|RZM9Gx1IOh?k
zMmmDJ(o4GT3~P~SA|nR?w{OX<<3#+8Yu^VT6DG`xT4;PBVkA$8;KjH*rG~-<#0b!J=>ucuqqNXza3S@xY$w#Ivo
z)4Xl1Dp3GHe)9DLG^HiH;cIz8d!k)#k4jjTD)!aQyg$K?t`D+hO{#82qbw!lN)h3@Pyf7bhqZ
z3xC6$$9K8FK-s7}SY4vQ#Pf;hBMiJJIO31i%AH*y(*xwN=(M}8+{Fx#{($L=O4^Fb
z1g0n_->_VCa_38XjTBP?!|y+Fn~0_2kRP(}KP{AGC_ZCq;UWuD1ScQMk$k(|R{lC)
zp^7^)Fv{4~$>VEA{sBrZpdz-dsW#NMi}!kw0z(CfXO_~1BV}a;TA@y)!o&RJ7vqJP
z9Xg|s&+=%zB2!y6Uc2cy0CpMx0K65;5O)iB0YEqzHfiVj+P9)2*e?QL@PkhhnGFDd
zNyJUDxWhsycLTVwP4K_cc7avsAu!BVIsXl$=%0|P
z{|3_jpCNt!gmnCukZ%75@-HtF{x?X5KMmLaGvr@hHvTi@D~C)hwe{aXih@P(#WENF
zH^@JiPv+e}L;8ZXz=3`EmyqlK2J%lYGf4k8$UnWz5c*e;86y7*GKKozK>q1vhWP&m
z`B#$sk*xoiB!7DOuQC&yB(ItIuae|1F9ZJ#
z4W_#sogDu*A+IvkuO|S3>(}!4Hvi~=>IAzj114Xu*8+i~0G8)wW#M3BVPj<{x3(~P
zJ*wwV<{x+b7w}2}@PMTxAWQ&cFTVhUX5hMPLG%p6`wZiC{eWSh0PJY^YzYtmSo6cp
zVam>@+uK)dbUQ;w@HfPN4CHk%*x(~#{)%$A2LSMT0q`B2{+IzU`G*|X8SvzTWxIWBlK;#((yKXXy_f;$QXO+ON%5oj+`W>;LfojK_cC^Jg4hm&gB~)(8Bn
zKj6jw$9g9Q=gw<>yq3Rm2LR5iR~jM@%zMqdzZGyl-!{1aEw}@`9RQfY7a{nf0bj4r
z$XELHqWVw!|1=(y|0ABSZ4&VH8f);g&)61Rzn0he1OIFWVB~D#WC*UcK)^q0FbSae
z`yB_oOF0
+
+ Project Contribution Credit Gate
+ Synthetic authorship and CRediT statement review packet
+
+
+ Approved
+ 1
+
+
+
+ Needs Remediation
+ 1
+
+
+
+ Blocked
+ 1
+
+ Checks: consent, CRediT roles, artifact contributors, credit omissions
+ Outputs: credit-packet.json, credit-report.md, summary.svg, demo video artifact
+ Synthetic data only. No live ORCID, SAML, OAuth, profile, or private project calls.
+
diff --git a/project-contribution-credit-gate/sample-data.js b/project-contribution-credit-gate/sample-data.js
new file mode 100644
index 00000000..27c3e1f2
--- /dev/null
+++ b/project-contribution-credit-gate/sample-data.js
@@ -0,0 +1,60 @@
+const scenarios = [
+ {
+ name: 'consent-block',
+ projectId: 'project-neuro-imaging',
+ action: 'publish-preprint',
+ generatedAt: '2026-05-22T12:30:00Z',
+ contributors: [
+ {id: 'u1', name: 'Ava Chen', role: 'Owner', orcid: '0000-0001-1111-1111', activeMember: true},
+ {id: 'u2', name: 'Mika Rao', role: 'Contributor', orcid: '0000-0002-2222-2222', activeMember: true},
+ ],
+ creditStatements: [
+ {contributorId: 'u1', creditRoles: ['Conceptualization', 'Writing - original draft'], consented: true, authorOrder: 1},
+ {contributorId: 'u2', creditRoles: ['Data curation'], consented: false, authorOrder: 2},
+ ],
+ projectArtifacts: [
+ {path: 'manuscript/main.md', touchedBy: ['u1']},
+ {path: 'data/participants.csv', touchedBy: ['u2']},
+ ],
+ },
+ {
+ name: 'omitted-contributor-remediation',
+ projectId: 'project-climate-model',
+ action: 'publish-preprint',
+ generatedAt: '2026-05-22T12:30:00Z',
+ contributors: [
+ {id: 'u1', name: 'Noor Silva', role: 'Owner', orcid: '0000-0001-3333-3333', activeMember: true},
+ {id: 'u2', name: 'Jon Bell', role: 'Contributor', orcid: '0000-0002-4444-4444', activeMember: true},
+ {id: 'u3', name: 'Ren Ito', role: 'Reviewer', orcid: '0000-0003-5555-5555', activeMember: true},
+ ],
+ creditStatements: [
+ {contributorId: 'u1', creditRoles: ['Supervision'], consented: true, authorOrder: 1},
+ {contributorId: 'u2', creditRoles: [], consented: true, authorOrder: 2},
+ ],
+ projectArtifacts: [
+ {path: 'code/model.py', touchedBy: ['u2', 'u3']},
+ {path: 'results/forecast.svg', touchedBy: ['u3']},
+ ],
+ },
+ {
+ name: 'approved-credit-packet',
+ projectId: 'project-approved-credit',
+ action: 'publish-preprint',
+ generatedAt: '2026-05-22T12:30:00Z',
+ contributors: [
+ {id: 'u1', name: 'Lina Park', role: 'Owner', orcid: '0000-0001-6666-6666', activeMember: true},
+ {id: 'u2', name: 'Samir Okafor', role: 'Contributor', orcid: '0000-0002-7777-7777', activeMember: true},
+ ],
+ creditStatements: [
+ {contributorId: 'u1', creditRoles: ['Conceptualization', 'Funding acquisition'], consented: true, authorOrder: 1},
+ {contributorId: 'u2', creditRoles: ['Software', 'Formal analysis'], consented: true, authorOrder: 2},
+ ],
+ projectArtifacts: [
+ {path: 'manuscript/main.md', touchedBy: ['u1']},
+ {path: 'code/analysis.py', touchedBy: ['u2']},
+ {path: 'results/table.csv', touchedBy: ['u2']},
+ ],
+ },
+];
+
+module.exports = {scenarios};
diff --git a/project-contribution-credit-gate/test.js b/project-contribution-credit-gate/test.js
new file mode 100644
index 00000000..c69ba75f
--- /dev/null
+++ b/project-contribution-credit-gate/test.js
@@ -0,0 +1,92 @@
+const test = require('node:test');
+const assert = require('node:assert/strict');
+
+const {
+ evaluateContributionCredit,
+ buildCreditReport,
+} = require('./index');
+
+test('blocks publication when listed author has not consented to credit statement', () => {
+ const result = evaluateContributionCredit({
+ projectId: 'project-neuro-imaging',
+ action: 'publish-preprint',
+ generatedAt: '2026-05-22T12:30:00Z',
+ contributors: [
+ {id: 'u1', name: 'Ava Chen', role: 'Owner', orcid: '0000-0001-1111-1111', activeMember: true},
+ {id: 'u2', name: 'Mika Rao', role: 'Contributor', orcid: '0000-0002-2222-2222', activeMember: true},
+ ],
+ creditStatements: [
+ {contributorId: 'u1', creditRoles: ['Conceptualization', 'Writing - original draft'], consented: true, authorOrder: 1},
+ {contributorId: 'u2', creditRoles: ['Data curation'], consented: false, authorOrder: 2},
+ ],
+ projectArtifacts: [
+ {path: 'manuscript/main.md', touchedBy: ['u1']},
+ {path: 'data/participants.csv', touchedBy: ['u2']},
+ ],
+ });
+
+ assert.equal(result.decision, 'blocked');
+ assert.deepEqual(result.blockers, [
+ 'Mika Rao is listed in the credit statement without consent',
+ ]);
+ assert.equal(result.requiredActions[0].type, 'collect_credit_consent');
+});
+
+test('requires remediation when active artifact contributor is omitted from credit statement', () => {
+ const result = evaluateContributionCredit({
+ projectId: 'project-climate-model',
+ action: 'publish-preprint',
+ generatedAt: '2026-05-22T12:30:00Z',
+ contributors: [
+ {id: 'u1', name: 'Noor Silva', role: 'Owner', orcid: '0000-0001-3333-3333', activeMember: true},
+ {id: 'u2', name: 'Jon Bell', role: 'Contributor', orcid: '0000-0002-4444-4444', activeMember: true},
+ {id: 'u3', name: 'Ren Ito', role: 'Reviewer', orcid: '0000-0003-5555-5555', activeMember: true},
+ ],
+ creditStatements: [
+ {contributorId: 'u1', creditRoles: ['Supervision'], consented: true, authorOrder: 1},
+ {contributorId: 'u2', creditRoles: [], consented: true, authorOrder: 2},
+ ],
+ projectArtifacts: [
+ {path: 'code/model.py', touchedBy: ['u2', 'u3']},
+ {path: 'results/forecast.svg', touchedBy: ['u3']},
+ ],
+ });
+
+ assert.equal(result.decision, 'needs-remediation');
+ assert.deepEqual(result.blockers, [
+ 'Jon Bell has no CRediT roles assigned',
+ 'Ren Ito contributed to project artifacts but is missing from credit statement',
+ ]);
+ assert.equal(result.coverage.artifactContributorCount, 2);
+ assert.equal(result.coverage.creditedContributorCount, 2);
+});
+
+test('builds deterministic report for approved contribution credit packet', () => {
+ const result = evaluateContributionCredit({
+ projectId: 'project-approved-credit',
+ action: 'publish-preprint',
+ generatedAt: '2026-05-22T12:30:00Z',
+ contributors: [
+ {id: 'u1', name: 'Lina Park', role: 'Owner', orcid: '0000-0001-6666-6666', activeMember: true},
+ {id: 'u2', name: 'Samir Okafor', role: 'Contributor', orcid: '0000-0002-7777-7777', activeMember: true},
+ ],
+ creditStatements: [
+ {contributorId: 'u1', creditRoles: ['Conceptualization', 'Funding acquisition'], consented: true, authorOrder: 1},
+ {contributorId: 'u2', creditRoles: ['Software', 'Formal analysis'], consented: true, authorOrder: 2},
+ ],
+ projectArtifacts: [
+ {path: 'manuscript/main.md', touchedBy: ['u1']},
+ {path: 'code/analysis.py', touchedBy: ['u2']},
+ {path: 'results/table.csv', touchedBy: ['u2']},
+ ],
+ });
+
+ assert.equal(result.decision, 'approved');
+ assert.equal(result.blockers.length, 0);
+ assert.equal(result.coverage.consentCoverage, 1);
+
+ const report = buildCreditReport(result);
+ assert.match(report, /project-approved-credit/);
+ assert.match(report, /Decision: approved/);
+ assert.match(report, /Consent coverage: 100%/);
+});