11// @vitest -environment node
22
33import { describe , expect , it } from 'vitest' ;
4- import type { FeedData , QualityReview } from '@/blog/model/types' ;
4+ import type { FeedData } from '@/blog/model/types' ;
55import { getAllFeedSlugs , getSortedFeedData } from './post-repository' ;
6+ import {
7+ filterVisiblePosts ,
8+ getCoreTechReviewAverage ,
9+ isEligibleForFeaturedPost ,
10+ isPostVisible ,
11+ meetsPublicTechReviewThreshold ,
12+ PUBLICATION_POLICY ,
13+ } from './policy' ;
614
715const FEATURED_SLUGS = [
816 'ctr-pipeline' ,
@@ -11,22 +19,51 @@ const FEATURED_SLUGS = [
1119 'msa-domain-workspace-submodule' ,
1220] ;
1321
14- function readCoreAverage ( review : QualityReview | undefined ) : number | null {
15- const scores = [ review ?. philosophy , review ?. design , review ?. implementation ] ;
16-
17- if ( scores . some ( ( score ) => typeof score !== 'number' ) ) {
18- return null ;
19- }
20-
21- const [ philosophy , design , implementation ] = scores as number [ ] ;
22- return ( philosophy + design + implementation ) / 3 ;
23- }
24-
2522function describePost ( post : FeedData ) : string {
2623 return `${ post . slug } (${ post . title } )` ;
2724}
2825
2926describe ( 'publication policy' , ( ) => {
27+ it ( 'keeps private posts hidden unless a caller explicitly requests a preview' , ( ) => {
28+ const unspecifiedPost = { } ;
29+ const privatePost = { visibility : 'private' } ;
30+ const publicPost = { visibility : 'public' } ;
31+
32+ expect ( isPostVisible ( unspecifiedPost ) ) . toBe ( false ) ;
33+ expect ( isPostVisible ( privatePost ) ) . toBe ( false ) ;
34+ expect ( isPostVisible ( publicPost ) ) . toBe ( true ) ;
35+ expect ( isPostVisible ( privatePost , { includePrivate : true } ) ) . toBe ( true ) ;
36+ expect ( filterVisiblePosts ( [ privatePost , publicPost ] ) ) . toEqual ( [ publicPost ] ) ;
37+ } ) ;
38+
39+ it ( 'keeps editorial thresholds in the policy module' , ( ) => {
40+ expect (
41+ meetsPublicTechReviewThreshold ( {
42+ philosophy : 3.5 ,
43+ design : 3.5 ,
44+ implementation : 3.5 ,
45+ } )
46+ ) . toBe ( true ) ;
47+ expect ( meetsPublicTechReviewThreshold ( { } ) ) . toBe ( false ) ;
48+
49+ expect (
50+ isEligibleForFeaturedPost ( {
51+ category : 'Tech' ,
52+ qualityReview : {
53+ brandFit : PUBLICATION_POLICY . featured . minimumBrandFit ,
54+ } ,
55+ } )
56+ ) . toBe ( true ) ;
57+ expect (
58+ isEligibleForFeaturedPost ( {
59+ category : 'Life' ,
60+ qualityReview : {
61+ brandFit : PUBLICATION_POLICY . featured . minimumBrandFit ,
62+ } ,
63+ } )
64+ ) . toBe ( false ) ;
65+ } ) ;
66+
3067 it ( 'keeps every private post out of public listings and static paths' , ( ) => {
3168 const allPosts = getSortedFeedData ( { includePrivate : true } ) ;
3269 const privatePosts = allPosts . filter (
@@ -57,17 +94,17 @@ describe('publication policy', () => {
5794 const offenses = getSortedFeedData ( )
5895 . filter ( ( post ) => post . category === 'Tech' )
5996 . flatMap ( ( post ) => {
60- const average = readCoreAverage ( post . qualityReview ) ;
97+ const average = getCoreTechReviewAverage ( post . qualityReview ) ;
6198
62- if ( average === null ) {
63- return [
64- `${ describePost ( post ) } : qualityReview core scores are incomplete` ,
65- ] ;
66- }
99+ if ( ! meetsPublicTechReviewThreshold ( post . qualityReview ) ) {
100+ if ( average === null ) {
101+ return [
102+ `${ describePost ( post ) } : qualityReview core scores are incomplete` ,
103+ ] ;
104+ }
67105
68- if ( average <= 3 ) {
69106 return [
70- `${ describePost ( post ) } : core average ${ average . toFixed ( 2 ) } <= 3.0 ` ,
107+ `${ describePost ( post ) } : core average ${ average . toFixed ( 2 ) } <= ${ PUBLICATION_POLICY . publicTech . minimumCoreReviewAverageExclusive . toFixed ( 1 ) } ` ,
71108 ] ;
72109 }
73110
@@ -80,26 +117,9 @@ describe('publication policy', () => {
80117 it ( 'requires featured posts to meet branding thresholds' , ( ) => {
81118 const featuredPosts = getSortedFeedData ( ) . filter ( ( post ) => post . featured ) ;
82119 const offenses = featuredPosts . flatMap ( ( post ) => {
83- const brandFit = post . qualityReview ?. brandFit ;
84- const currentOffenses : string [ ] = [ ] ;
85-
86- if ( post . category !== 'Tech' ) {
87- currentOffenses . push (
88- `${ describePost ( post ) } : featured posts must be Tech`
89- ) ;
90- }
91-
92- if ( post . series ) {
93- currentOffenses . push (
94- `${ describePost ( post ) } : featured posts must not be series`
95- ) ;
96- }
97-
98- if ( typeof brandFit !== 'number' || brandFit < 4 ) {
99- currentOffenses . push ( `${ describePost ( post ) } : brandFit must be >= 4.0` ) ;
100- }
101-
102- return currentOffenses ;
120+ return isEligibleForFeaturedPost ( post )
121+ ? [ ]
122+ : [ `${ describePost ( post ) } : does not meet featured criteria` ] ;
103123 } ) ;
104124
105125 expect ( featuredPosts . map ( ( post ) => post . slug ) . sort ( ) ) . toEqual (
0 commit comments