@@ -19,7 +19,7 @@ function fixture() {
1919 fs . mkdirSync ( path . join ( root , 'src' ) , { recursive : true } ) ;
2020 fs . mkdirSync ( path . dirname ( p . config ) , { recursive : true } ) ;
2121 writeJson ( p . project , { schemaVersion : '2.0' , kitVersion : '2.0.0' } ) ;
22- writeJson ( p . config , { schemaVersion : '2.0' , projectName : 'Fixture' , ignore : { useGitignore : true , useDocgenignore : true , binary : { enabled : true , maxTextFileBytes : 1024 * 1024 } } , context : { maxTokens : { default : 4000 , generate : 4000 } } , execution : { generationBatchSize : 2 , maxPlannedPages : 30 } , audit : { llmEnabled : false } } ) ;
22+ writeJson ( p . config , { schemaVersion : '2.0' , projectName : 'Fixture' , ignore : { useGitignore : true , useDocgenignore : true , binary : { enabled : true , maxTextFileBytes : 1024 * 1024 } } , context : { maxTokens : { default : 4000 , modelCore : 4000 , modelEnterprise : 4000 , plan : 4000 , generate : 4000 , audit : 2000 } } , budget : { maxProviderCalls : 10 , maxEstimatedInputTokens : 200000 , maxEstimatedOutputTokens : 50000 , maxContextTokensPerCall : 10000 } , execution : { generationBatchSize : 2 , maxPlannedPages : 30 } , audit : { llmEnabled : false } , retry : { maxAttempts : 1 } } ) ;
2323 writeJson ( p . state , { schemaVersion : '2.0' , kitVersion : '2.0.0' , stages : { } , pages : { } } ) ;
2424 return root ;
2525}
@@ -34,6 +34,39 @@ function catalogFixture(root) {
3434 return p ;
3535}
3636
37+ function installFakeProvider ( root ) {
38+ const file = path . join ( root , 'fake-provider.mjs' ) ;
39+ fs . writeFileSync ( file , `#!/usr/bin/env node
40+ import fs from 'node:fs';
41+ import path from 'node:path';
42+ const prompt=fs.readFileSync(0,'utf8');
43+ const stage=process.env.DOCGEN_STAGE;
44+ const cwd=process.cwd();
45+ const target=(prompt.match(/Write exactly one JSON file: \\` ( [ ^ \\`]+)\\` / i ) || [ ] ) [ 1 ] ;
46+ const write = ( rel , value ) => { const file = path . join ( cwd , rel ) ; fs . mkdirSync ( path . dirname ( file ) , { recursive :true } ) ; fs . writeFileSync ( file , JSON . stringify ( value , null , 2 ) + '\\n' ) ; } ;
47+ if ( stage === 'modelCore' ) {
48+ write ( target , { system :{ components :[ { id :'resource' , kind :'component' , name :'Resource' , statement :'HTTP resource' , classification :'FACT' , confidence :1 , evidence :[ { path :'src/Resource.java' , startLine :1 } ] } ] , relationships :[ ] , workflows :[ ] , unknowns :[ ] } , business :{ actors :[ ] , capabilities :[ ] , concepts :[ ] , businessRules :[ ] , decisions :[ ] , branchConditions :[ ] , lifecycles :[ ] , invariants :[ ] , useCases :[ ] , unknowns :[ ] } , flows :{ businessFlows :[ ] , controlFlows :[ ] , requestFlows :[ ] , trafficFlows :[ ] , dataFlows :[ ] , eventFlows :[ ] } , catalogs :{ endpoints :[ ] , messageHandlers :[ ] , externalDependencies :[ ] , dataStores :[ ] , scheduledJobs :[ ] } } ) ;
49+ } else if ( stage === 'modelEnterprise' ) {
50+ write ( target , { security :{ unknowns :[ ] } , operations :{ unknowns :[ ] } , testing :{ unknowns :[ ] } , 'data-governance' :{ unknowns :[ ] } , decisions :{ unknowns :[ ] } , configuration :{ unknowns :[ ] } , 'change-impact' :{ unknowns :[ ] } , ownership :{ unknowns :[ ] } } ) ;
51+ } else if ( stage === 'plan' ) {
52+ write ( target , { schemaVersion :'2.0' , metadata :{ description :'Fixture docs' } , pages :[ { id :'overview' , title :'System Overview' , summary :'Fixture overview.' , category :'orientation' , mode :'explanation' , type :'overview' , order :1 , audience :[ 'engineer' ] , coverageTags :[ 'architecture' ] , query :'resource architecture' , requiredSections :[ ] , risk :'low' , relatedPages :[ ] } ] } ) ;
53+ } else if ( stage === 'generate' ) {
54+ const json = ( prompt . match ( / P a g e c o n t r a c t s : \\ n ( [ \\ s \\ S ] * ?) \\ n \\ n F o r e v e r y c o n t r a c t : / ) || [ ] ) [ 1 ] ;
55+ const contracts = JSON . parse ( json ) ;
56+ for ( const contract of contracts ) {
57+ const page = contract . page ;
58+ const md = '---\\ntitle: ' + JSON . stringify ( page . title ) + '\\ndescription: ' + JSON . stringify ( page . summary ) + '\\npageId: ' + JSON . stringify ( page . id ) + '\\ncategory: ' + JSON . stringify ( page . category ) + '\\nmode: ' + JSON . stringify ( page . mode ) + '\\ntype: ' + JSON . stringify ( page . type ) + '\\norder: ' + page . order + '\\n---\\n# ' + page . title + '\\n\\n' + page . summary + '\\n\\nThe repository exposes an HTTP resource.\\n' ;
59+ const output = path . join ( cwd , contract . outputPath ) ; fs . mkdirSync ( path . dirname ( output ) , { recursive :true } ) ; fs . writeFileSync ( output , md ) ;
60+ write ( contract . traceabilityPath , { schemaVersion :'2.0' , pageId :page . id , pagePath :contract . outputPath , claims :[ { id :page . id + ':resource' , section :page . title , statement :'The repository exposes an HTTP resource.' , classification :'FACT' , confidence :1 , evidence :[ { path :'src/Resource.java' , startLine :1 } ] , sourceModelRefs :[ 'system:resource' ] } ] } ) ;
61+ }
62+ } else if ( stage === 'audit' ) {
63+ const output = ( prompt . match ( / r e p o r t : \\ ` ( [ ^ \\ ` ] + ) \\ ` / i) || [ ] ) [ 1 ] || '.docgen/audit/llm-risk.json' ; write ( output , { schemaVersion :'2.0' , pages :[ ] } ) ;
64+ } else { process . exitCode = 2 ; console . error ( 'unexpected stage ' + stage ) ; }
65+ `);
66+ fs.chmodSync(file, 0o755);
67+ return file;
68+ }
69+
3770test('inventory excludes binary and docgenignore paths', () => {
3871 const root = fixture();
3972 fs.writeFileSync(path.join(root, 'src', 'Resource.java'), '@Path("/quotes")\nclass Resource { @GET void get() {} }\n');
@@ -98,6 +131,17 @@ test('deterministic audit rejects FACT evidence outside inventory', async () =>
98131 await assert.rejects(() => audit(root), /Quality failed/);
99132});
100133
134+ test('full indexed pipeline uses four provider calls then zero on resume', () => {
135+ const root = fixture(); const p = projectPaths(root); const provider = installFakeProvider(root);
136+ fs.writeFileSync(path.join(root, 'src', 'Resource.java'), '@Path("/quotes")\nclass Resource { @GET void get() {} }\n');
137+ const config = readJson(p.config); config.commandCode = { executable: provider, trust: false, skipOnboarding: false, yolo: false, verbose: false, maxTurns: { default: 4 } }; writeJson(p.config, config);
138+ const first = spawnSync(process.execPath, [cli, 'all'], { cwd: root, encoding: 'utf8' }); assert.equal(first.status, 0, first.stderr || first.stdout);
139+ const firstBudget = readJson(p.budget); assert.equal(firstBudget.usage.providerCalls, 4);
140+ const second = spawnSync(process.execPath, [cli, 'all'], { cwd: root, encoding: 'utf8' }); assert.equal(second.status, 0, second.stderr || second.stdout);
141+ const secondBudget = readJson(p.budget); assert.equal(secondBudget.usage.providerCalls, 4);
142+ assert.equal(readJson(path.join(p.audit, 'quality-summary.json')).pass, true);
143+ });
144+
101145test('v1 migration preserves docs and ignore policy while archiving workflow state', () => {
102146 const root = fixture(); const p = projectPaths(root);
103147 writeJson(p.config, { schemaVersion: '1.6', projectName: 'Migrated', commandCode: { executable: 'custom-cmdc', model: 'cheap-model' }, ignore: { useGitignore: true, binary: { maxTextFileBytes: 123456 } } });
0 commit comments