@@ -108,7 +108,50 @@ function unmetRequirements(ev: EvalManifest): string[] {
108108 const available : Record < string , boolean > = {
109109 outpost : Boolean ( process . env . OUTPOST_API_KEY ) ,
110110 } ;
111- return ( ev . metadata . requires ?? [ ] ) . filter ( ( r ) => ! available [ r ] ) ;
111+ const unmet = ( ev . metadata . requires ?? [ ] ) . filter ( ( r ) => ! available [ r ] ) ;
112+
113+ // A `${SEED_*}` placeholder the environment cannot fill is an unmet
114+ // requirement, not a task.
115+ //
116+ // `local/` files leave an unset variable as written, so the agent is handed
117+ // the literal `${SEED_ACME_SQS_ACCESS_KEY}`. That reads as an obvious
118+ // placeholder, and an agent that notices is right to stop rather than
119+ // configure delivery that will silently fail — measured on 24 August, where
120+ // exactly that scored 0/1 while three agents that did not notice scored 6/6.
121+ //
122+ // Scoring it is the 13 August mistake again: a missing credential became six
123+ // agent failures against named vendors, and the fix then was to skip rather
124+ // than score. The same reasoning applies to a credential the scenario
125+ // supplies itself.
126+ return [ ...unmet , ...unfilledSeedPlaceholders ( ev ) ] ;
127+ }
128+
129+ /** `SEED_*` names a scenario's workspace asks for and the environment lacks. */
130+ function unfilledSeedPlaceholders ( ev : EvalManifest ) : string [ ] {
131+ if ( ! ev . localDir || ! existsSync ( ev . localDir ) ) return [ ] ;
132+ const missing = new Set < string > ( ) ;
133+
134+ const walk = ( dir : string ) => {
135+ for ( const entry of readdirSync ( dir , { withFileTypes : true } ) ) {
136+ const path = join ( dir , entry . name ) ;
137+ if ( entry . isDirectory ( ) ) {
138+ walk ( path ) ;
139+ continue ;
140+ }
141+ let text : string ;
142+ try {
143+ text = readFileSync ( path , 'utf8' ) ;
144+ } catch {
145+ continue ; // binary; nothing to expand
146+ }
147+ for ( const [ , name ] of text . matchAll ( / \$ \{ ( S E E D _ [ A - Z 0 - 9 _ ] + ) \} / g) ) {
148+ if ( ! process . env [ name ] ) missing . add ( name ) ;
149+ }
150+ }
151+ } ;
152+ walk ( ev . localDir ) ;
153+
154+ return [ ...missing ] ;
112155}
113156
114157type ToolsSkill = { name : string ; description : string ; body : string } ;
0 commit comments