@@ -25,7 +25,8 @@ function analyzeEntryCheckCompleteness(text, options = {}) {
2525 const sourceSchemaVersion = marker ? `DevCodexVisibleEnvelopeV${ marker [ 1 ] } ` : null
2626 const legacyReadOnly = marker && [ '1' , '2' ] . includes ( marker [ 1 ] )
2727 const lastOrdinal = legacyReadOnly ? 7 : 10
28- const claimed = / 入 口 检 查 | 预 检 查 ( \s * D E V | # # # \s * D e v C o d e x \s * · \s * 入 口 检 查 | D e v C o d e x V i s i b l e E n v e l o p e V (?: 1 | 2 | 3 ) \s * · \s * e n t r y - c h e c k | P C 0 \s * (?: 上 下 文 | 版 本 | \[ | ( ) | P C 0 \s * [ : : ] / i. test ( body )
28+ const freeTextPcLines = detectFreeTextPcLines ( body , lastOrdinal )
29+ const claimed = / 入 口 检 查 | 预 检 查 ( \s * D E V | # # # \s * D e v C o d e x \s * · \s * 入 口 检 查 | D e v C o d e x V i s i b l e E n v e l o p e V (?: 1 | 2 | 3 ) \s * · \s * e n t r y - c h e c k | P C 0 \s * (?: 上 下 文 | 版 本 | \[ | ( ) | P C 0 \s * [ : : ] / i. test ( body ) || freeTextPcLines . length >= 3
2930 if ( ! claimed ) {
3031 return {
3132 claimed : false ,
@@ -74,6 +75,9 @@ function analyzeEntryCheckCompleteness(text, options = {}) {
7475 if ( ! presentPcs . includes ( id ) ) missingPcs . push ( id )
7576 }
7677 if ( missingPcs . length ) missingItems . push ( 'pc-columns-incomplete' )
78+ if ( freeTextPcLines . length >= 3 && presentPcs . length < freeTextPcLines . length ) {
79+ missingItems . push ( 'pc-free-text-lines' )
80+ }
7781
7882 // Legacy V1/V2 PC0 carried context. V3 PC0 carries installed/runtime/source version facts and alignment.
7983 const currentRowPrefix = legacyReadOnly ? '(?:[-*]\\s*)?(?:\\|\\s*)?' : '(?:[-*]\\s+|\\|\\s*)'
@@ -139,6 +143,20 @@ function analyzeEntryCheckCompleteness(text, options = {}) {
139143 }
140144}
141145
146+ function detectFreeTextPcLines ( body , lastOrdinal ) {
147+ const seen = [ ]
148+ for ( const line of String ( body || '' ) . split ( / \r ? \n / u) ) {
149+ if ( / ^ \s * (?: [ - * ] \s + | \| ) / u. test ( line ) ) continue
150+ const match = line . match ( / ^ \s * P C \s * ( 1 0 | [ 0 - 9 ] ) \b (? ! \s * [ - – — ~ ~ 至 到 ] ) [ ^ \n ] * [ : : ] / iu)
151+ if ( ! match ) continue
152+ const ordinal = Number ( match [ 1 ] )
153+ if ( ! Number . isInteger ( ordinal ) || ordinal > lastOrdinal ) continue
154+ const id = `PC${ ordinal } `
155+ if ( ! seen . includes ( id ) ) seen . push ( id )
156+ }
157+ return seen
158+ }
159+
142160function projectWorkflowCompletionVisibleState ( projection ) {
143161 const valid = projection ?. schemaVersion === 'WorkflowCompletionProjectionV1' &&
144162 Array . isArray ( projection . phaseTerminals ) && projection . phaseTerminals . length === 4 &&
@@ -337,7 +355,7 @@ function buildLifecycleVisibleReplyUtils(ctx) {
337355 // Accept V1/V2 as read-only compatibility; current V3 requires free-text PC0~PC10 completeness.
338356 const entryCompleteness = analyzeEntryCheckCompleteness ( text , { mode : state . mode } )
339357 state . visible . entryCheckCompleteness = entryCompleteness
340- if ( / 入 口 检 查 ( | 预 检 查 ( D E V 模 式 ) | P C 0 (?: 上 下 文 | 版 本 ) | # # # \s * D e v C o d e x \s * · \s * 入 口 检 查 | D e v C o d e x V i s i b l e E n v e l o p e V (?: 1 | 2 | 3 ) \s * · \s * e n t r y - c h e c k | P C 0 \s * [ \[ ( ] / . test ( text ) ) {
358+ if ( entryCompleteness . claimed ) {
341359 if ( entryCompleteness . complete ) {
342360 state . visible . precheck = true
343361 state . visible . precheckStatus = 'verified-present'
0 commit comments