Skip to content

Commit 2aa9f0f

Browse files
authored
Prepare model access before the first workflow run (#1342)
1 parent d3d8a4e commit 2aa9f0f

18 files changed

Lines changed: 259 additions & 342 deletions

.github/skills/micro-environment-simulator/simulator.js

Lines changed: 43 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,7 @@ const PROVIDER_SECRET_BY_NAME = {
1616
anthropic: "ANTHROPIC_API_KEY",
1717
openai: "OPENAI_API_KEY"
1818
};
19-
const INFERENCE_PROVIDERS = Object.keys(PROVIDER_SECRET_BY_NAME);
20-
const INFERENCE_PROVIDER_SEED_OFFSET = 4;
21-
const COPILOT_SECRET_PRIMARY_MODULO = 5;
22-
const COPILOT_SECRET_SECONDARY_MODULO = 7;
23-
const THIRD_PARTY_SECRET_BEGINNER_MODULO = 3;
24-
const THIRD_PARTY_SECRET_SECONDARY_MODULO = 8;
25-
const ANTHROPIC_MISSING_REMAINDER = 0;
26-
const OPENAI_MISSING_REMAINDER = 1;
27-
const COPILOT_PERMISSION_GITHUB_MODULO = 4;
28-
const COPILOT_PERMISSION_OTHER_MODULO = 3;
19+
const INFERENCE_PROVIDERS = ["github"];
2920
const WORD_COUNT_COMPLEXITY_THRESHOLD = 1400;
3021
const COMMAND_LINE_COMPLEXITY_THRESHOLD = 18;
3122
const CALLOUT_COMPLEXITY_THRESHOLD = 18;
@@ -60,13 +51,6 @@ function deterministicChoice(seed, choices) {
6051
return choices[index];
6152
}
6253

63-
function hasThirdPartyProviderSecret(level, seed, missingRemainder) {
64-
if (level !== "beginner") {
65-
return true;
66-
}
67-
return seed % THIRD_PARTY_SECRET_BEGINNER_MODULO !== missingRemainder;
68-
}
69-
7054
function resolveRepositoryOwnerType(student, isEnterprise, seed) {
7155
if (isEnterprise) {
7256
return "enterprise-organization";
@@ -153,6 +137,11 @@ function analyzeStepMarkdown(stepId, markdown, files = []) {
153137
text,
154138
/\.lock\.yml[\s\S]{0,500}\b(commit(?: changes)?|push|approve the commit)\b|\b(commit(?: changes)?|push|approve the commit)\b[\s\S]{0,500}\.lock\.yml/gi
155139
);
140+
const copilotRequestsWriteCueCount = countMatches(
141+
text,
142+
/^\s*copilot-requests:\s*write\s*(?:#.*)?$/gim
143+
);
144+
const copilotGithubTokenCueCount = countMatches(text, /\bCOPILOT_GITHUB_TOKEN\b/g);
156145
const complexity = clamp(
157146
0.12 +
158147
Math.min(wordCount / WORD_COUNT_COMPLEXITY_THRESHOLD, 0.32) +
@@ -205,6 +194,8 @@ function analyzeStepMarkdown(stepId, markdown, files = []) {
205194
uiAlternativeCount,
206195
workflowCompileCueCount,
207196
workflowLockPublishCueCount,
197+
copilotRequestsWriteCueCount,
198+
copilotGithubTokenCueCount,
208199
authDemand,
209200
browserSupport,
210201
complexity,
@@ -368,26 +359,16 @@ function defaultEnvironmentForStudent(student, dayOfYear, runIndex = 0) {
368359
(level === "advanced" ||
369360
level === "actions-user" ||
370361
(isEnterprise ? seed % 6 !== 0 : seed % (uiPreferred ? 4 : 5) !== 0));
371-
const inferenceProvider = deterministicChoice(seed + INFERENCE_PROVIDER_SEED_OFFSET, INFERENCE_PROVIDERS);
372-
const hasCopilotGithubToken =
373-
isLoggedIn &&
374-
(inferenceProvider === "github"
375-
? seed % COPILOT_SECRET_PRIMARY_MODULO !== 0
376-
: seed % COPILOT_SECRET_SECONDARY_MODULO === 0);
377-
const hasAnthropicApiKey =
378-
isLoggedIn &&
379-
(inferenceProvider === "anthropic"
380-
? hasThirdPartyProviderSecret(level, seed, ANTHROPIC_MISSING_REMAINDER)
381-
: seed % THIRD_PARTY_SECRET_SECONDARY_MODULO === 0);
382-
const hasOpenAiApiKey =
383-
isLoggedIn &&
384-
(inferenceProvider === "openai"
385-
? hasThirdPartyProviderSecret(level, seed, OPENAI_MISSING_REMAINDER)
386-
: seed % THIRD_PARTY_SECRET_SECONDARY_MODULO === 1);
387-
const hasCopilotRequestsWrite =
388-
inferenceProvider === "github"
389-
? seed % COPILOT_PERMISSION_GITHUB_MODULO !== 0
390-
: seed % COPILOT_PERMISSION_OTHER_MODULO !== 0;
362+
const inferenceProvider = "github";
363+
// Model a mixed organization cohort: enterprise organizations have centralized
364+
// billing, while half of other organizations have enabled it.
365+
const centralizedCopilotBilling =
366+
repositoryOwnerType !== "personal" && (isEnterprise || seed % 2 === 0);
367+
// The Step 7 transition fills these fields after the required model-access activity.
368+
const hasCopilotGithubToken = null;
369+
const hasAnthropicApiKey = null;
370+
const hasOpenAiApiKey = null;
371+
const hasCopilotRequestsWrite = null;
391372
const baseConfidence = clamp(
392373
0.3 +
393374
(level === "advanced"
@@ -430,6 +411,7 @@ function defaultEnvironmentForStudent(student, dayOfYear, runIndex = 0) {
430411
},
431412
actions: {
432413
inferenceProvider,
414+
centralizedCopilotBilling,
433415
permissions: {
434416
copilotRequestsWrite: hasCopilotRequestsWrite
435417
},
@@ -609,11 +591,26 @@ function aggregateDropoutRates(monteCarlo, totalStudents, runsCount) {
609591
return dropoutRateByStep;
610592
}
611593

594+
function aggregateFailureCategories(monteCarlo) {
595+
const failureCategoriesByStep = {};
596+
for (const result of monteCarlo) {
597+
for (const [stepId, categories] of Object.entries(result.failureCategoriesByStep || {})) {
598+
failureCategoriesByStep[stepId] ||= {};
599+
for (const [category, count] of Object.entries(categories)) {
600+
failureCategoriesByStep[stepId][category] =
601+
(failureCategoriesByStep[stepId][category] || 0) + count;
602+
}
603+
}
604+
}
605+
return failureCategoriesByStep;
606+
}
607+
612608
function simulateStudentsMonteCarlo(students, date, runsCount = 100, config = {}) {
613609
const dayOfYear = toDayOfYear(date);
614610
return students.map((student) => {
615611
let successes = 0;
616612
const failuresByStep = {};
613+
const failureCategoriesByStep = {};
617614

618615
for (let runIndex = 0; runIndex < runsCount; runIndex++) {
619616
const initialState =
@@ -638,6 +635,10 @@ function simulateStudentsMonteCarlo(students, date, runsCount = 100, config = {}
638635
} else if (result.firstFailingStep) {
639636
failuresByStep[result.firstFailingStep] =
640637
(failuresByStep[result.firstFailingStep] || 0) + 1;
638+
const category = result.category || "unknown";
639+
failureCategoriesByStep[result.firstFailingStep] ||= {};
640+
failureCategoriesByStep[result.firstFailingStep][category] =
641+
(failureCategoriesByStep[result.firstFailingStep][category] || 0) + 1;
641642
}
642643
}
643644

@@ -649,6 +650,7 @@ function simulateStudentsMonteCarlo(students, date, runsCount = 100, config = {}
649650
successes,
650651
successRate: successes / runsCount,
651652
failuresByStep,
653+
failureCategoriesByStep,
652654
mostCommonFailureStep: sortedFailures.length > 0 ? sortedFailures[0][0] : null
653655
};
654656
});
@@ -724,7 +726,8 @@ function runCli() {
724726
aggregate: {
725727
overallSuccessRate:
726728
monteCarlo.reduce((sum, r) => sum + r.successRate, 0) / monteCarlo.length,
727-
dropoutRateByStep: aggregateDropoutRates(monteCarlo, students.length, runsCount)
729+
dropoutRateByStep: aggregateDropoutRates(monteCarlo, students.length, runsCount),
730+
failureCategoriesByStep: aggregateFailureCategories(monteCarlo)
728731
}
729732
};
730733
} else {
@@ -761,7 +764,8 @@ const exportedApi = {
761764
replayWorkshop,
762765
simulateStudents,
763766
simulateStudentsMonteCarlo,
764-
aggregateDropoutRates
767+
aggregateDropoutRates,
768+
aggregateFailureCategories
765769
};
766770

767771
module.exports = exportedApi;

0 commit comments

Comments
 (0)