From 93f81ce0803e9a6971e6e4d66064540ea98f2b14 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 29 Nov 2023 09:27:08 -0800 Subject: [PATCH 01/48] Updating gramatical errors --- 031-DevOpsWithGitHub/Student/Challenge-03.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/031-DevOpsWithGitHub/Student/Challenge-03.md b/031-DevOpsWithGitHub/Student/Challenge-03.md index 5ee9b4c461..4584ca858c 100644 --- a/031-DevOpsWithGitHub/Student/Challenge-03.md +++ b/031-DevOpsWithGitHub/Student/Challenge-03.md @@ -21,7 +21,7 @@ Review the following introduction to GitHub project boards: [GitHub project boar - Create a new project using the "Team backlog" template. -- Ensure your project is with linked with your repository +- Ensure your project is linked to your repository - Create a draft issue for this challenge (3) and each of the remaining challenges (i.e., create 9 issues total - skip challenges 0,1 and 2 as you already completed them). When creating each issue, make sure to: - Assign an owner for each issue from your team. From cf3c5642f4f7ea28c06516853638adf5ae536632 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Mon, 28 Oct 2024 14:23:30 -0700 Subject: [PATCH 02/48] Create .devcontain.json --- .devcontainer/.devcontain.json | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 .devcontainer/.devcontain.json diff --git a/.devcontainer/.devcontain.json b/.devcontainer/.devcontain.json new file mode 100644 index 0000000000..5e6740a18d --- /dev/null +++ b/.devcontainer/.devcontain.json @@ -0,0 +1,32 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/dotnet +{ + "name" : "DevOps with GitHub WTH in Codespaces", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/dotnet:0-6.0", + "workspaceFolder": "/workspace/031-DevOpsWithGitHub", + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached", + "features": { + "ghcr.io/devcontainers/features/azure-cli:1": { + "installBicep": true, + "version": "latest" + } + } + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [5000, 5001], + // "portsAttributes": { + // "5001": { + // "protocol": "https" + // } + // } + + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "dotnet restore", + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} From a4bd57a97a4d9e412ae865d14be74ac19f3a3a97 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Mon, 28 Oct 2024 14:29:18 -0700 Subject: [PATCH 03/48] rename devcontainer file properly --- .devcontainer/{.devcontain.json => .devcontainer.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .devcontainer/{.devcontain.json => .devcontainer.json} (100%) diff --git a/.devcontainer/.devcontain.json b/.devcontainer/.devcontainer.json similarity index 100% rename from .devcontainer/.devcontain.json rename to .devcontainer/.devcontainer.json From f83a0c130f42c5c2db4a8f6a05950e84a0ca91b1 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Mon, 28 Oct 2024 14:35:40 -0700 Subject: [PATCH 04/48] Rename .devcontainer.json to devcontainer.json --- .devcontainer/{.devcontainer.json => devcontainer.json} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .devcontainer/{.devcontainer.json => devcontainer.json} (100%) diff --git a/.devcontainer/.devcontainer.json b/.devcontainer/devcontainer.json similarity index 100% rename from .devcontainer/.devcontainer.json rename to .devcontainer/devcontainer.json From 6852ce08370d68ce66ba22aeccd272a7fbd9f723 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Tue, 4 Feb 2025 14:25:33 -0800 Subject: [PATCH 05/48] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 23d79fd3b3..532050f8c2 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ Here is the current list of What The Hack hackathons available in this repositor - [Fabric Real-time Intelligence](/069-FabricRealTimeIntelligence/README.md) - [Cosmic Troubleshooting](/056-CosmicTroubleshooting/README.md) - [Data Governance with Microsoft Purview](/051-MicrosoftPurview/README.md) +- [Data Science In Microsoft Fabric](/072-DataScienceInFabric/README.md) - [SQL Modernization and Migration](/043-SQLModernization/README.md) - [OSS Database Migration](/033-OSSDatabaseMigration/README.md) - [MLOps from Scratch](/032-MLOpsFromScratch/README.md) From e9c1fa124a840a6487b29fdfacd24b9870b395f5 Mon Sep 17 00:00:00 2001 From: GitHub Actions Bot <> Date: Wed, 3 Jun 2026 18:31:33 +0000 Subject: [PATCH 06/48] Created WhatTheHack template stub --- .../Coach/Lectures.pptx | Bin 0 -> 196287 bytes .../Coach/README.md | 79 ++++++++++++++ .../Coach/Solution-00.md | 20 ++++ .../Coach/Solution-01.md | 20 ++++ .../Coach/Solution-02.md | 20 ++++ .../Coach/Solution-03.md | 20 ++++ .../Coach/Solution-04.md | 20 ++++ .../Coach/Solution-05.md | 20 ++++ .../Coach/Solutions/.gitkeep | 0 xxx-GitHubCopilotCostOptimization/README.md | 40 +++++++ .../Student/Challenge-00.md | 100 ++++++++++++++++++ .../Student/Challenge-01.md | 99 +++++++++++++++++ .../Student/Challenge-02.md | 99 +++++++++++++++++ .../Student/Challenge-03.md | 99 +++++++++++++++++ .../Student/Challenge-04.md | 99 +++++++++++++++++ .../Student/Challenge-05.md | 99 +++++++++++++++++ .../Student/Resources/.gitkeep | 0 17 files changed, 834 insertions(+) create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Lectures.pptx create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/README.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solution-00.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/.gitkeep create mode 100644 xxx-GitHubCopilotCostOptimization/README.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Challenge-00.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/.gitkeep diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Lectures.pptx b/xxx-GitHubCopilotCostOptimization/Coach/Lectures.pptx new file mode 100644 index 0000000000000000000000000000000000000000..34cfe52f45a056e33791ebf176cee017e41362e0 GIT binary patch literal 196287 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�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%0A2O;OS!shB_ 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 J40sEG@;^hlltKUi literal 0 HcmV?d00001 diff --git a/xxx-GitHubCopilotCostOptimization/Coach/README.md b/xxx-GitHubCopilotCostOptimization/Coach/README.md new file mode 100644 index 0000000000..1214f76ab8 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/README.md @@ -0,0 +1,79 @@ +# What The Hack - GitHubCopilotCostOptimization - Coach Guide + +## Introduction + +Welcome to the coach's guide for the GitHubCopilotCostOptimization What The Hack. Here you will find links to specific guidance for coaches for each of the challenges. + +This hack includes an optional [lecture presentation](Lectures.pptx) that features short presentations to introduce key topics associated with each challenge. It is recommended that the host present each short presentation before attendees kick off that challenge. + +**NOTE:** If you are a Hackathon participant, this is the answer guide. Don't cheat yourself by looking at these during the hack! Go learn something. :) + +## Coach's Guides + +- Challenge 00: **[Prerequisites - Ready, Set, GO!](./Solution-00.md)** + - Prepare your workstation to work with Azure. +- Challenge 01: **[Title of Challenge](./Solution-01.md)** + - Description of challenge +- Challenge 02: **[Title of Challenge](./Solution-02.md)** + - Description of challenge +- Challenge 03: **[Title of Challenge](./Solution-03.md)** + - Description of challenge +- Challenge 04: **[Title of Challenge](./Solution-04.md)** + - Description of challenge +- Challenge 05: **[Title of Challenge](./Solution-05.md)** + - Description of challenge + +## Coach Prerequisites + +This hack has pre-reqs that a coach is responsible for understanding and/or setting up BEFORE hosting an event. Please review the [What The Hack Hosting Guide](https://aka.ms/wthhost) for information on how to host a hack event. + +The guide covers the common preparation steps a coach needs to do before any What The Hack event, including how to properly configure Microsoft Teams. + +### Student Resources + +Before the hack, it is the Coach's responsibility to download and package up the contents of the `/Student/Resources` folder of this hack into a "Resources.zip" file. The coach should then provide a copy of the Resources.zip file to all students at the start of the hack. + +Always refer students to the [What The Hack website](https://aka.ms/wth) for the student guide: [https://aka.ms/wth](https://aka.ms/wth) + +**NOTE:** Students should **not** be given a link to the What The Hack repo before or during a hack. The student guide does **NOT** have any links to the Coach's guide or the What The Hack repo on GitHub. + +### Additional Coach Prerequisites (Optional) + +_Please list any additional pre-event setup steps a coach would be required to set up such as, creating or hosting a shared dataset, or deploying a lab environment._ + +## Azure Requirements + +This hack requires students to have access to an Azure subscription where they can create and consume Azure resources. These Azure requirements should be shared with a stakeholder in the organization that will be providing the Azure subscription(s) that will be used by the students. + +_Please list Azure subscription requirements._ + +_For example:_ + +- Azure resources that will be consumed by a student implementing the hack's challenges +- Azure permissions required by a student to complete the hack's challenges. + +## Suggested Hack Agenda (Optional) + +_This section is optional. You may wish to provide an estimate of how long each challenge should take for an average squad of students to complete and/or a proposal of how many challenges a coach should structure each session for a multi-session hack event. For example:_ + +- Sample Day 1 + - Challenge 1 (1 hour) + - Challenge 2 (30 mins) + - Challenge 3 (2 hours) +- Sample Day 2 + - Challenge 4 (45 mins) + - Challenge 5 (1 hour) + - Challenge 6 (45 mins) + +## Repository Contents + +_The default files & folders are listed below. You may add to this if you want to specify what is in additional sub-folders you may add._ + +- `./Coach` + - Coach's Guide and related files +- `./Coach/Solutions` + - Solution files with completed example answers to a challenge +- `./Student` + - Student's Challenge Guide +- `./Student/Resources` + - Resource files, sample code, scripts, etc meant to be provided to students. (Must be packaged up by the coach and provided to students at start of event) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-00.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-00.md new file mode 100644 index 0000000000..8ca1a44d71 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-00.md @@ -0,0 +1,20 @@ +# Challenge 00 - - Coach's Guide + +**[Home](./README.md)** - [Next Solution >](./Solution-01.md) + +## Notes & Guidance + +This is the only section you need to include. + +Use general non-bulleted text for the beginning of a solution area for this challenge + +- Then move into bullets + - And sub-bullets and even + - sub-sub-bullets + +Break things apart with more than one bullet list + +- Like this +- One +- Right +- Here diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md new file mode 100644 index 0000000000..01d1e30c27 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md @@ -0,0 +1,20 @@ +# Challenge 01 - <Title of Challenge> - Coach's Guide + +[< Previous Solution](./Solution-00.md) - **[Home](./README.md)** - [Next Solution >](./Solution-02.md) + +## Notes & Guidance + +This is the only section you need to include. + +Use general non-bulleted text for the beginning of a solution area for this challenge + +- Then move into bullets + - And sub-bullets and even + - sub-sub-bullets + +Break things apart with more than one bullet list + +- Like this +- One +- Right +- Here diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md new file mode 100644 index 0000000000..1ef8ca5035 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md @@ -0,0 +1,20 @@ +# Challenge 02 - <Title of Challenge> - Coach's Guide + +[< Previous Solution](./Solution-01.md) - **[Home](./README.md)** - [Next Solution >](./Solution-03.md) + +## Notes & Guidance + +This is the only section you need to include. + +Use general non-bulleted text for the beginning of a solution area for this challenge + +- Then move into bullets + - And sub-bullets and even + - sub-sub-bullets + +Break things apart with more than one bullet list + +- Like this +- One +- Right +- Here diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md new file mode 100644 index 0000000000..9591196509 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md @@ -0,0 +1,20 @@ +# Challenge 03 - <Title of Challenge> - Coach's Guide + +[< Previous Solution](./Solution-02.md) - **[Home](./README.md)** - [Next Solution >](./Solution-04.md) + +## Notes & Guidance + +This is the only section you need to include. + +Use general non-bulleted text for the beginning of a solution area for this challenge + +- Then move into bullets + - And sub-bullets and even + - sub-sub-bullets + +Break things apart with more than one bullet list + +- Like this +- One +- Right +- Here diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md new file mode 100644 index 0000000000..90a770fdb3 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md @@ -0,0 +1,20 @@ +# Challenge 04 - <Title of Challenge> - Coach's Guide + +[< Previous Solution](./Solution-03.md) - **[Home](./README.md)** - [Next Solution >](./Solution-05.md) + +## Notes & Guidance + +This is the only section you need to include. + +Use general non-bulleted text for the beginning of a solution area for this challenge + +- Then move into bullets + - And sub-bullets and even + - sub-sub-bullets + +Break things apart with more than one bullet list + +- Like this +- One +- Right +- Here diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md new file mode 100644 index 0000000000..c320bf9745 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md @@ -0,0 +1,20 @@ +# Challenge 05 - <Title of Challenge> - Coach's Guide + +[< Previous Solution](./Solution-04.md) - **[Home](./README.md)** + +## Notes & Guidance + +This is the only section you need to include. + +Use general non-bulleted text for the beginning of a solution area for this challenge + +- Then move into bullets + - And sub-bullets and even + - sub-sub-bullets + +Break things apart with more than one bullet list + +- Like this +- One +- Right +- Here diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/.gitkeep b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/xxx-GitHubCopilotCostOptimization/README.md b/xxx-GitHubCopilotCostOptimization/README.md new file mode 100644 index 0000000000..2cc1b99151 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/README.md @@ -0,0 +1,40 @@ +# What The Hack - GitHubCopilotCostOptimization + +## Introduction + +The IoT Hack of the Century will take you on a whirlwind tour in the world of IoT and how it is being used in the modern world of mineral extraction in exotic locations like the Arctic and the wilds of South Africa. + +## Learning Objectives + +In this hack you will be solving the common business problem that companies in the mineral extraction industry face and how IoT solutions from Azure are brought to bare + +1. Provision an IoT Hub +2. Set up an IoT Edge device +3. Bring Azure Sphere to your solution for scale and resiliency + +## Challenges + +- Challenge 00: **[Prerequisites - Ready, Set, GO!](Student/Challenge-00.md)** + - Prepare your workstation to work with Azure. +- Challenge 01: **[Title of Challenge](Student/Challenge-01.md)** + - Description of challenge +- Challenge 02: **[Title of Challenge](Student/Challenge-02.md)** + - Description of challenge +- Challenge 03: **[Title of Challenge](Student/Challenge-03.md)** + - Description of challenge +- Challenge 04: **[Title of Challenge](Student/Challenge-04.md)** + - Description of challenge +- Challenge 05: **[Title of Challenge](Student/Challenge-05.md)** + - Description of challenge + +## Prerequisites + +- Your own Azure subscription with Owner access +- Visual Studio Code +- Azure CLI +- An AVNET X231 device + +## Contributors + +- Jane Q. Public +- Joe T. Muppet diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-00.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-00.md new file mode 100644 index 0000000000..632f605df9 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-00.md @@ -0,0 +1,100 @@ +# Challenge 00 - Prerequisites - Ready, Set, GO! + +**[Home](../README.md)** - [Next Challenge >](./Challenge-01.md) + +**_This is a template for "Challenge Zero" which focuses on getting prerequisites set up for the hack. The italicized text provides hints & examples of what should or should NOT go in each section._** + +**_We have included links to some common What The Hack pre-reqs in this template. All common prerequisite links go to the WTH-CommonPrerequisites page where there are more details on what each tool's purpose is._** + +**_You should remove any common pre-reqs that are not required for your hack. Then add additional pre-reqs that are required for your hack in the Description section below._** + +**_You should remove all italicized & sample text in this template and replace with your content._** + +## Introduction + +Thank you for participating in the GitHubCopilotCostOptimization What The Hack. Before you can hack, you will need to set up some prerequisites. + +## Common Prerequisites + +We have compiled a list of common tools and software that will come in handy to complete most What The Hack Azure-based hacks! + +You might not need all of them for the hack you are participating in. However, if you work with Azure on a regular basis, these are all things you should consider having in your toolbox. + +<!-- If you are editing this template manually, be aware that these links are only designed to work if this Markdown file is in the /xxx-HackName/Student/ folder of your hack. --> + +- [Azure Subscription](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-subscription) +- [Windows Subsystem for Linux](../../000-HowToHack/WTH-Common-Prerequisites.md#windows-subsystem-for-linux) +- [Managing Cloud Resources](../../000-HowToHack/WTH-Common-Prerequisites.md#managing-cloud-resources) + - [Azure Portal](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-portal) + - [Azure CLI](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-cli) + - [Note for Windows Users](../../000-HowToHack/WTH-Common-Prerequisites.md#note-for-windows-users) + - [Azure PowerShell CmdLets](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-powershell-cmdlets) + - [Azure Cloud Shell](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-cloud-shell) +- [Visual Studio Code](../../000-HowToHack/WTH-Common-Prerequisites.md#visual-studio-code) + - [VS Code plugin for ARM Templates](../../000-HowToHack/WTH-Common-Prerequisites.md#visual-studio-code-plugins-for-arm-templates) +- [Azure Storage Explorer](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-storage-explorer) + +## Description + +_This section should clearly state any additional prerequisite tools that need to be installed or set up in the Azure environment that the student will hack in._ + +_While ordered lists are generally not welcome in What The Hack challenge descriptions, you can use one here in Challenge Zero IF and only IF the steps you are asking the student to perform are not core to the learning objectives of the hack._ + +_For example, if the hack is on IoT Devices and you want the student to deploy an ARM/Bicep template that sets up the environment they will hack in without them needing to understand how ARM/Bicep templates work, you can provide step-by-step instructions on how to deploy the ARM/Bicep template._ + +_Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack. You should leave the sample text below in that refers to the Resources.zip file._ + +**\*NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resources.zip file provided by the coach.\* + +**\*NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.\* + +_Sample challenge zero text for the IoT Hack Of The Century:_ + +Now that you have the common pre-requisites installed on your workstation, there are prerequisites specifc to this hack. + +Your coach will provide you with a Resources.zip file that contains resources you will need to complete the hack. If you plan to work locally, you should unpack it on your workstation. If you plan to use the Azure Cloud Shell, you should upload it to the Cloud Shell and unpack it there. + +Please install these additional tools: + +- [Azure IoT Tools](https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.azure-iot-tools) extension for Visual Studio Code +- .NET SDK 6.0 or later installed on your development machine. This can be downloaded from [here](https://www.microsoft.com/net/download/all) for multiple platforms. + +In the `/Challenge00/` folder of the Resources.zip file, you will find an ARM template, `setupIoTEnvironment.json` that sets up the initial hack environment in Azure you will work with in subsequent challenges. + +Please deploy the template by running the following Azure CLI commands from the location of the template file: +``` +az group create --name myIoT-rg --location eastus +az group deployment create -g myIoT-rg --name HackEnvironment -f setupIoTEnvironment.json +``` + +## Success Criteria + +_Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach._ + +_The success criteria should not be a list of instructions._ + +_Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."_ + +_Sample success criteria for the IoT prerequisites challenge:_ + +To complete this challenge successfully, you should be able to: + +- Verify that you have a bash shell with the Azure CLI available. +- Verify that the ARM template has deployed the following resources in Azure: + - Azure IoT Hub + - Virtual Network + - Jumpbox VM + +## Learning Resources + +_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ + +_Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario._ + +**\*Note:** Use descriptive text for each link instead of just URLs.\* + +_Sample IoT resource links:_ + +- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) +- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) +- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md new file mode 100644 index 0000000000..fcf81ed831 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md @@ -0,0 +1,99 @@ +# Challenge 01 - <Title of Challenge> + +[< Previous Challenge](./Challenge-00.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-02.md) + +***This is a template for a single challenge. The italicized text provides hints & examples of what should or should NOT go in each section. You should remove all italicized & sample text and replace with your content.*** + +## Pre-requisites (Optional) + +*Your hack's "Challenge 0" should cover pre-requisites for the entire hack, and thus this section is optional and may be omitted. If you wish to spell out specific previous challenges that must be completed before starting this challenge, you may do so here.* + +## Introduction + +*This section should provide an overview of the technologies or tasks that will be needed to complete the this challenge. This includes the technical context for the challenge, as well as any new "lessons" the attendees should learn before completing the challenge.* + +*Optionally, the coach or event host is encouraged to present a mini-lesson (with a PPT or video) to set up the context & introduction to each challenge. A summary of the content of that mini-lesson is a good candidate for this Introduction section* + +*For example:* + +When setting up an IoT device, it is important to understand how 'thingamajigs' work. Thingamajigs are a key part of every IoT device and ensure they are able to communicate properly with edge servers. Thingamajigs require IP addresses to be assigned to them by a server and thus must have unique MAC addresses. In this challenge, you will get hands on with a thingamajig and learn how one is configured. + +## Description + +*This section should clearly state the goals of the challenge and any high-level instructions you want the students to follow. You may provide a list of specifications required to meet the goals. If this is more than 2-3 paragraphs, it is likely you are not doing it right.* + +***NOTE:** Do NOT use ordered lists as that is an indicator of 'step-by-step' instructions. Instead, use bullet lists to list out goals and/or specifications.* + +***NOTE:** You may use Markdown sub-headers to organize key sections of your challenge description.* + +*Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack.* + +***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* + +***NOTE:** As an exception, you may provide a GitHub 'raw' link to an individual file such as a PDF or Office document, so long as it does not open the contents of the file in the What The Hack repo on the GitHub website.* + +***NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.* + +*Sample challenge text for the IoT Hack Of The Century:* + +In this challenge, you will properly configure the thingamajig for your IoT device so that it can communicate with the mother ship. + +You can find a sample `thingamajig.config` file in the `/ChallengeXX` folder of the Resources.zip file provided by your coach. This is a good starting reference, but you will need to discover how to set exact settings. + +Please configure the thingamajig with the following specifications: +- Use dynamic IP addresses +- Only trust the following whitelisted servers: "mothership", "IoTQueenBee" +- Deny access to "IoTProxyShip" + +You can view an architectural diagram of an IoT thingamajig here: [Thingamajig.PDF](/Student/Resources/Architecture.PDF?raw=true). + +## Success Criteria + +*Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach.* + +*The success criteria should not be a list of instructions.* + +*Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."* + +*Sample success criteria for the IoT sample challenge:* + +To complete this challenge successfully, you should be able to: +- Verify that the IoT device boots properly after its thingamajig is configured. +- Verify that the thingamajig can connect to the mothership. +- Demonstrate that the thingamajic will not connect to the IoTProxyShip + +## Learning Resources + +_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ + +*Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario.* + +***Note:** Use descriptive text for each link instead of just URLs.* + +*Sample IoT resource links:* + +- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) +- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) +- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) + +## Tips + +*This section is optional and may be omitted.* + +*Add tips and hints here to give students food for thought. Sample IoT tips:* + +- IoTDevices can fail from a broken heart if they are not together with their thingamajig. Your device will display a broken heart emoji on its screen if this happens. +- An IoTDevice can have one or more thingamajigs attached which allow them to connect to multiple networks. + +## Advanced Challenges (Optional) + +*If you want, you may provide additional goals to this challenge for folks who are eager.* + +*This section is optional and may be omitted.* + +*Sample IoT advanced challenges:* + +Too comfortable? Eager to do more? Try these additional challenges! + +- Observe what happens if your IoTDevice is separated from its thingamajig. +- Configure your IoTDevice to connect to BOTH the mothership and IoTQueenBee at the same time. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md new file mode 100644 index 0000000000..459fb175d5 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md @@ -0,0 +1,99 @@ +# Challenge 02 - <Title of Challenge> + +[< Previous Challenge](./Challenge-01.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-03.md) + +***This is a template for a single challenge. The italicized text provides hints & examples of what should or should NOT go in each section. You should remove all italicized & sample text and replace with your content.*** + +## Pre-requisites (Optional) + +*Your hack's "Challenge 0" should cover pre-requisites for the entire hack, and thus this section is optional and may be omitted. If you wish to spell out specific previous challenges that must be completed before starting this challenge, you may do so here.* + +## Introduction + +*This section should provide an overview of the technologies or tasks that will be needed to complete the this challenge. This includes the technical context for the challenge, as well as any new "lessons" the attendees should learn before completing the challenge.* + +*Optionally, the coach or event host is encouraged to present a mini-lesson (with a PPT or video) to set up the context & introduction to each challenge. A summary of the content of that mini-lesson is a good candidate for this Introduction section* + +*For example:* + +When setting up an IoT device, it is important to understand how 'thingamajigs' work. Thingamajigs are a key part of every IoT device and ensure they are able to communicate properly with edge servers. Thingamajigs require IP addresses to be assigned to them by a server and thus must have unique MAC addresses. In this challenge, you will get hands on with a thingamajig and learn how one is configured. + +## Description + +*This section should clearly state the goals of the challenge and any high-level instructions you want the students to follow. You may provide a list of specifications required to meet the goals. If this is more than 2-3 paragraphs, it is likely you are not doing it right.* + +***NOTE:** Do NOT use ordered lists as that is an indicator of 'step-by-step' instructions. Instead, use bullet lists to list out goals and/or specifications.* + +***NOTE:** You may use Markdown sub-headers to organize key sections of your challenge description.* + +*Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack.* + +***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* + +***NOTE:** As an exception, you may provide a GitHub 'raw' link to an individual file such as a PDF or Office document, so long as it does not open the contents of the file in the What The Hack repo on the GitHub website.* + +***NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.* + +*Sample challenge text for the IoT Hack Of The Century:* + +In this challenge, you will properly configure the thingamajig for your IoT device so that it can communicate with the mother ship. + +You can find a sample `thingamajig.config` file in the `/ChallengeXX` folder of the Resources.zip file provided by your coach. This is a good starting reference, but you will need to discover how to set exact settings. + +Please configure the thingamajig with the following specifications: +- Use dynamic IP addresses +- Only trust the following whitelisted servers: "mothership", "IoTQueenBee" +- Deny access to "IoTProxyShip" + +You can view an architectural diagram of an IoT thingamajig here: [Thingamajig.PDF](/Student/Resources/Architecture.PDF?raw=true). + +## Success Criteria + +*Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach.* + +*The success criteria should not be a list of instructions.* + +*Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."* + +*Sample success criteria for the IoT sample challenge:* + +To complete this challenge successfully, you should be able to: +- Verify that the IoT device boots properly after its thingamajig is configured. +- Verify that the thingamajig can connect to the mothership. +- Demonstrate that the thingamajic will not connect to the IoTProxyShip + +## Learning Resources + +_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ + +*Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario.* + +***Note:** Use descriptive text for each link instead of just URLs.* + +*Sample IoT resource links:* + +- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) +- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) +- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) + +## Tips + +*This section is optional and may be omitted.* + +*Add tips and hints here to give students food for thought. Sample IoT tips:* + +- IoTDevices can fail from a broken heart if they are not together with their thingamajig. Your device will display a broken heart emoji on its screen if this happens. +- An IoTDevice can have one or more thingamajigs attached which allow them to connect to multiple networks. + +## Advanced Challenges (Optional) + +*If you want, you may provide additional goals to this challenge for folks who are eager.* + +*This section is optional and may be omitted.* + +*Sample IoT advanced challenges:* + +Too comfortable? Eager to do more? Try these additional challenges! + +- Observe what happens if your IoTDevice is separated from its thingamajig. +- Configure your IoTDevice to connect to BOTH the mothership and IoTQueenBee at the same time. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md new file mode 100644 index 0000000000..88656873ba --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md @@ -0,0 +1,99 @@ +# Challenge 03 - <Title of Challenge> + +[< Previous Challenge](./Challenge-02.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-04.md) + +***This is a template for a single challenge. The italicized text provides hints & examples of what should or should NOT go in each section. You should remove all italicized & sample text and replace with your content.*** + +## Pre-requisites (Optional) + +*Your hack's "Challenge 0" should cover pre-requisites for the entire hack, and thus this section is optional and may be omitted. If you wish to spell out specific previous challenges that must be completed before starting this challenge, you may do so here.* + +## Introduction + +*This section should provide an overview of the technologies or tasks that will be needed to complete the this challenge. This includes the technical context for the challenge, as well as any new "lessons" the attendees should learn before completing the challenge.* + +*Optionally, the coach or event host is encouraged to present a mini-lesson (with a PPT or video) to set up the context & introduction to each challenge. A summary of the content of that mini-lesson is a good candidate for this Introduction section* + +*For example:* + +When setting up an IoT device, it is important to understand how 'thingamajigs' work. Thingamajigs are a key part of every IoT device and ensure they are able to communicate properly with edge servers. Thingamajigs require IP addresses to be assigned to them by a server and thus must have unique MAC addresses. In this challenge, you will get hands on with a thingamajig and learn how one is configured. + +## Description + +*This section should clearly state the goals of the challenge and any high-level instructions you want the students to follow. You may provide a list of specifications required to meet the goals. If this is more than 2-3 paragraphs, it is likely you are not doing it right.* + +***NOTE:** Do NOT use ordered lists as that is an indicator of 'step-by-step' instructions. Instead, use bullet lists to list out goals and/or specifications.* + +***NOTE:** You may use Markdown sub-headers to organize key sections of your challenge description.* + +*Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack.* + +***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* + +***NOTE:** As an exception, you may provide a GitHub 'raw' link to an individual file such as a PDF or Office document, so long as it does not open the contents of the file in the What The Hack repo on the GitHub website.* + +***NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.* + +*Sample challenge text for the IoT Hack Of The Century:* + +In this challenge, you will properly configure the thingamajig for your IoT device so that it can communicate with the mother ship. + +You can find a sample `thingamajig.config` file in the `/ChallengeXX` folder of the Resources.zip file provided by your coach. This is a good starting reference, but you will need to discover how to set exact settings. + +Please configure the thingamajig with the following specifications: +- Use dynamic IP addresses +- Only trust the following whitelisted servers: "mothership", "IoTQueenBee" +- Deny access to "IoTProxyShip" + +You can view an architectural diagram of an IoT thingamajig here: [Thingamajig.PDF](/Student/Resources/Architecture.PDF?raw=true). + +## Success Criteria + +*Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach.* + +*The success criteria should not be a list of instructions.* + +*Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."* + +*Sample success criteria for the IoT sample challenge:* + +To complete this challenge successfully, you should be able to: +- Verify that the IoT device boots properly after its thingamajig is configured. +- Verify that the thingamajig can connect to the mothership. +- Demonstrate that the thingamajic will not connect to the IoTProxyShip + +## Learning Resources + +_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ + +*Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario.* + +***Note:** Use descriptive text for each link instead of just URLs.* + +*Sample IoT resource links:* + +- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) +- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) +- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) + +## Tips + +*This section is optional and may be omitted.* + +*Add tips and hints here to give students food for thought. Sample IoT tips:* + +- IoTDevices can fail from a broken heart if they are not together with their thingamajig. Your device will display a broken heart emoji on its screen if this happens. +- An IoTDevice can have one or more thingamajigs attached which allow them to connect to multiple networks. + +## Advanced Challenges (Optional) + +*If you want, you may provide additional goals to this challenge for folks who are eager.* + +*This section is optional and may be omitted.* + +*Sample IoT advanced challenges:* + +Too comfortable? Eager to do more? Try these additional challenges! + +- Observe what happens if your IoTDevice is separated from its thingamajig. +- Configure your IoTDevice to connect to BOTH the mothership and IoTQueenBee at the same time. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md new file mode 100644 index 0000000000..a032304040 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md @@ -0,0 +1,99 @@ +# Challenge 04 - <Title of Challenge> + +[< Previous Challenge](./Challenge-03.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-05.md) + +***This is a template for a single challenge. The italicized text provides hints & examples of what should or should NOT go in each section. You should remove all italicized & sample text and replace with your content.*** + +## Pre-requisites (Optional) + +*Your hack's "Challenge 0" should cover pre-requisites for the entire hack, and thus this section is optional and may be omitted. If you wish to spell out specific previous challenges that must be completed before starting this challenge, you may do so here.* + +## Introduction + +*This section should provide an overview of the technologies or tasks that will be needed to complete the this challenge. This includes the technical context for the challenge, as well as any new "lessons" the attendees should learn before completing the challenge.* + +*Optionally, the coach or event host is encouraged to present a mini-lesson (with a PPT or video) to set up the context & introduction to each challenge. A summary of the content of that mini-lesson is a good candidate for this Introduction section* + +*For example:* + +When setting up an IoT device, it is important to understand how 'thingamajigs' work. Thingamajigs are a key part of every IoT device and ensure they are able to communicate properly with edge servers. Thingamajigs require IP addresses to be assigned to them by a server and thus must have unique MAC addresses. In this challenge, you will get hands on with a thingamajig and learn how one is configured. + +## Description + +*This section should clearly state the goals of the challenge and any high-level instructions you want the students to follow. You may provide a list of specifications required to meet the goals. If this is more than 2-3 paragraphs, it is likely you are not doing it right.* + +***NOTE:** Do NOT use ordered lists as that is an indicator of 'step-by-step' instructions. Instead, use bullet lists to list out goals and/or specifications.* + +***NOTE:** You may use Markdown sub-headers to organize key sections of your challenge description.* + +*Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack.* + +***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* + +***NOTE:** As an exception, you may provide a GitHub 'raw' link to an individual file such as a PDF or Office document, so long as it does not open the contents of the file in the What The Hack repo on the GitHub website.* + +***NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.* + +*Sample challenge text for the IoT Hack Of The Century:* + +In this challenge, you will properly configure the thingamajig for your IoT device so that it can communicate with the mother ship. + +You can find a sample `thingamajig.config` file in the `/ChallengeXX` folder of the Resources.zip file provided by your coach. This is a good starting reference, but you will need to discover how to set exact settings. + +Please configure the thingamajig with the following specifications: +- Use dynamic IP addresses +- Only trust the following whitelisted servers: "mothership", "IoTQueenBee" +- Deny access to "IoTProxyShip" + +You can view an architectural diagram of an IoT thingamajig here: [Thingamajig.PDF](/Student/Resources/Architecture.PDF?raw=true). + +## Success Criteria + +*Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach.* + +*The success criteria should not be a list of instructions.* + +*Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."* + +*Sample success criteria for the IoT sample challenge:* + +To complete this challenge successfully, you should be able to: +- Verify that the IoT device boots properly after its thingamajig is configured. +- Verify that the thingamajig can connect to the mothership. +- Demonstrate that the thingamajic will not connect to the IoTProxyShip + +## Learning Resources + +_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ + +*Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario.* + +***Note:** Use descriptive text for each link instead of just URLs.* + +*Sample IoT resource links:* + +- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) +- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) +- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) + +## Tips + +*This section is optional and may be omitted.* + +*Add tips and hints here to give students food for thought. Sample IoT tips:* + +- IoTDevices can fail from a broken heart if they are not together with their thingamajig. Your device will display a broken heart emoji on its screen if this happens. +- An IoTDevice can have one or more thingamajigs attached which allow them to connect to multiple networks. + +## Advanced Challenges (Optional) + +*If you want, you may provide additional goals to this challenge for folks who are eager.* + +*This section is optional and may be omitted.* + +*Sample IoT advanced challenges:* + +Too comfortable? Eager to do more? Try these additional challenges! + +- Observe what happens if your IoTDevice is separated from its thingamajig. +- Configure your IoTDevice to connect to BOTH the mothership and IoTQueenBee at the same time. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md new file mode 100644 index 0000000000..027fffe5bf --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -0,0 +1,99 @@ +# Challenge 05 - <Title of Challenge> + +[< Previous Challenge](./Challenge-04.md) - **[Home](../README.md)** + +***This is a template for a single challenge. The italicized text provides hints & examples of what should or should NOT go in each section. You should remove all italicized & sample text and replace with your content.*** + +## Pre-requisites (Optional) + +*Your hack's "Challenge 0" should cover pre-requisites for the entire hack, and thus this section is optional and may be omitted. If you wish to spell out specific previous challenges that must be completed before starting this challenge, you may do so here.* + +## Introduction + +*This section should provide an overview of the technologies or tasks that will be needed to complete the this challenge. This includes the technical context for the challenge, as well as any new "lessons" the attendees should learn before completing the challenge.* + +*Optionally, the coach or event host is encouraged to present a mini-lesson (with a PPT or video) to set up the context & introduction to each challenge. A summary of the content of that mini-lesson is a good candidate for this Introduction section* + +*For example:* + +When setting up an IoT device, it is important to understand how 'thingamajigs' work. Thingamajigs are a key part of every IoT device and ensure they are able to communicate properly with edge servers. Thingamajigs require IP addresses to be assigned to them by a server and thus must have unique MAC addresses. In this challenge, you will get hands on with a thingamajig and learn how one is configured. + +## Description + +*This section should clearly state the goals of the challenge and any high-level instructions you want the students to follow. You may provide a list of specifications required to meet the goals. If this is more than 2-3 paragraphs, it is likely you are not doing it right.* + +***NOTE:** Do NOT use ordered lists as that is an indicator of 'step-by-step' instructions. Instead, use bullet lists to list out goals and/or specifications.* + +***NOTE:** You may use Markdown sub-headers to organize key sections of your challenge description.* + +*Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack.* + +***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* + +***NOTE:** As an exception, you may provide a GitHub 'raw' link to an individual file such as a PDF or Office document, so long as it does not open the contents of the file in the What The Hack repo on the GitHub website.* + +***NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.* + +*Sample challenge text for the IoT Hack Of The Century:* + +In this challenge, you will properly configure the thingamajig for your IoT device so that it can communicate with the mother ship. + +You can find a sample `thingamajig.config` file in the `/ChallengeXX` folder of the Resources.zip file provided by your coach. This is a good starting reference, but you will need to discover how to set exact settings. + +Please configure the thingamajig with the following specifications: +- Use dynamic IP addresses +- Only trust the following whitelisted servers: "mothership", "IoTQueenBee" +- Deny access to "IoTProxyShip" + +You can view an architectural diagram of an IoT thingamajig here: [Thingamajig.PDF](/Student/Resources/Architecture.PDF?raw=true). + +## Success Criteria + +*Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach.* + +*The success criteria should not be a list of instructions.* + +*Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."* + +*Sample success criteria for the IoT sample challenge:* + +To complete this challenge successfully, you should be able to: +- Verify that the IoT device boots properly after its thingamajig is configured. +- Verify that the thingamajig can connect to the mothership. +- Demonstrate that the thingamajic will not connect to the IoTProxyShip + +## Learning Resources + +_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ + +*Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario.* + +***Note:** Use descriptive text for each link instead of just URLs.* + +*Sample IoT resource links:* + +- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) +- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) +- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) + +## Tips + +*This section is optional and may be omitted.* + +*Add tips and hints here to give students food for thought. Sample IoT tips:* + +- IoTDevices can fail from a broken heart if they are not together with their thingamajig. Your device will display a broken heart emoji on its screen if this happens. +- An IoTDevice can have one or more thingamajigs attached which allow them to connect to multiple networks. + +## Advanced Challenges (Optional) + +*If you want, you may provide additional goals to this challenge for folks who are eager.* + +*This section is optional and may be omitted.* + +*Sample IoT advanced challenges:* + +Too comfortable? Eager to do more? Try these additional challenges! + +- Observe what happens if your IoTDevice is separated from its thingamajig. +- Configure your IoTDevice to connect to BOTH the mothership and IoTQueenBee at the same time. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/.gitkeep b/xxx-GitHubCopilotCostOptimization/Student/Resources/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 From 908b3e6e3e5dbef077f7e785c74326feeddeb8a5 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:28:13 -0700 Subject: [PATCH 07/48] Initial Commit --- .../Coach/README.md | 92 +++++++-- .../Coach/Solution-00.md | 78 +++++++- .../Coach/Solution-01.md | 147 +++++++++++++- .../Coach/Solution-02.md | 51 ++++- .../Coach/Solution-03.md | 43 +++- .../Coach/Solution-04.md | 46 ++++- .../Coach/Solution-05.md | 68 +++++-- .../Coach/Solution-06.md | 189 ++++++++++++++++++ xxx-GitHubCopilotCostOptimization/README.md | 60 +++--- .../Student/Challenge-00.md | 109 +++------- .../Student/Challenge-01.md | 74 ++++--- .../Student/Challenge-02.md | 73 +++++-- .../Student/Challenge-03.md | 86 ++++++-- .../Student/Challenge-04.md | 81 ++++++-- .../Student/Challenge-05.md | 108 +++++++++- .../Student/Challenge-06.md | 81 ++++++++ 16 files changed, 1128 insertions(+), 258 deletions(-) create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solution-06.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Challenge-06.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/README.md b/xxx-GitHubCopilotCostOptimization/Coach/README.md index 1214f76ab8..d33197c7c1 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/README.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/README.md @@ -1,27 +1,29 @@ -# What The Hack - GitHubCopilotCostOptimization - Coach Guide +# What The Hack - GitHub Copilot Cost Optimization - Coach Guide ## Introduction -Welcome to the coach's guide for the GitHubCopilotCostOptimization What The Hack. Here you will find links to specific guidance for coaches for each of the challenges. +Welcome to the coach's guide for the GitHub Copilot Cost Optimization What The Hack. Here you will find links to specific guidance for coaches for each of the challenges. -This hack includes an optional [lecture presentation](Lectures.pptx) that features short presentations to introduce key topics associated with each challenge. It is recommended that the host present each short presentation before attendees kick off that challenge. +This hack teaches teams to maximize code quality while minimizing GitHub Copilot credit spend under usage-based billing (UBB). The focus is on practical engineering techniques: context engineering, model selection, session hygiene, and spec-driven development. **NOTE:** If you are a Hackathon participant, this is the answer guide. Don't cheat yourself by looking at these during the hack! Go learn something. :) ## Coach's Guides -- Challenge 00: **[Prerequisites - Ready, Set, GO!](./Solution-00.md)** - - Prepare your workstation to work with Azure. -- Challenge 01: **[Title of Challenge](./Solution-01.md)** - - Description of challenge -- Challenge 02: **[Title of Challenge](./Solution-02.md)** - - Description of challenge -- Challenge 03: **[Title of Challenge](./Solution-03.md)** - - Description of challenge -- Challenge 04: **[Title of Challenge](./Solution-04.md)** - - Description of challenge -- Challenge 05: **[Title of Challenge](./Solution-05.md)** - - Description of challenge +- Challenge 00: **[Prerequisites & Baseline](./Solution-00.md)** + - Set up the hack environment and establish baseline credit spend measurements +- Challenge 01: **[Context Engineering](./Solution-01.md)** + - Optimize instruction architecture and attachment precision +- Challenge 02: **[Model Selection & Output Constraints](./Solution-02.md)** + - Compare models and apply output constraints to reduce costs +- Challenge 03: **[Session Configuration (Tools + Cache)](./Solution-03.md)** + - Manage MCP tool sprawl and understand cache invalidation +- Challenge 04: **[Context Window Management](./Solution-04.md)** + - Use /compact proactively to maintain quality and control costs +- Challenge 05: **[Spec-Driven Development](./Solution-05.md)** + - Leverage deterministic controls as token controls +- Challenge 06: **[Token Golf Competition](./Solution-06.md)** + - Competitive coding challenge optimizing for lowest credit spend ## Coach Prerequisites @@ -33,21 +35,71 @@ The guide covers the common preparation steps a coach needs to do before any Wha Before the hack, it is the Coach's responsibility to download and package up the contents of the `/Student/Resources` folder of this hack into a "Resources.zip" file. The coach should then provide a copy of the Resources.zip file to all students at the start of the hack. +The Student/Resources folder should contain: + +- **Starter codebase** with intentionally sub-optimal GitHub Copilot configuration: + - Bloated `.github/copilot-instructions.md` (~1500 tokens) for Challenge 01 + - Multiple MCP tools enabled (some unnecessary) for Challenge 03 + - Sample code with opportunities for spec-first vs. trial-and-error comparison +- **Baseline coding task** (baseline-task.md) for Challenge 00 +- **Token Golf task specification** for Challenge 06 with acceptance criteria + Always refer students to the [What The Hack website](https://aka.ms/wth) for the student guide: [https://aka.ms/wth](https://aka.ms/wth) **NOTE:** Students should **not** be given a link to the What The Hack repo before or during a hack. The student guide does **NOT** have any links to the Coach's guide or the What The Hack repo on GitHub. -### Additional Coach Prerequisites (Optional) +### Additional Coach Prerequisites + +**Coach must complete Challenge 06 (Token Golf) before the hack:** + +- Complete the Token Golf coding task yourself to establish "par" score +- Document your credit spend and techniques used +- This "par" becomes the benchmark teams compete against -_Please list any additional pre-event setup steps a coach would be required to set up such as, creating or hosting a shared dataset, or deploying a lab environment._ +**Prepare measurement tools:** + +- Confirm all students have UBB enabled on their GitHub Copilot subscriptions +- Verify token visibility in VS Code Output panel (GitHub Copilot Chat) +- Test access to GitHub Copilot usage dashboard ## Azure Requirements -This hack requires students to have access to an Azure subscription where they can create and consume Azure resources. These Azure requirements should be shared with a stakeholder in the organization that will be providing the Azure subscription(s) that will be used by the students. +This hack does not require Azure resources. All work is done locally with GitHub Copilot in Visual Studio Code. + +## Suggested Hack Agenda + +This hack can be delivered as a half-day or full-day event: + +### Half-Day Format (4 hours) +- Challenge 00: Prerequisites & Baseline (30 minutes) +- Challenge 01: Context Engineering (45 minutes) +- Challenge 02: Model Selection & Output Constraints (45 minutes) +- Challenge 03: Session Configuration (30 minutes) +- Challenge 05: Spec-Driven Development (45 minutes) +- Challenge 06: Token Golf Competition (45 minutes) -_Please list Azure subscription requirements._ +### Full-Day Format (6-7 hours) +- Challenge 00: Prerequisites & Baseline (45 minutes) +- Challenge 01: Context Engineering (60 minutes) +- Challenge 02: Model Selection & Output Constraints (60 minutes) +- Break (15 minutes) +- Challenge 03: Session Configuration (45 minutes) +- Challenge 04: Context Window Management (45 minutes) +- Challenge 05: Spec-Driven Development (60 minutes) +- Break (15 minutes) +- Challenge 06: Token Golf Competition (60 minutes) +- Debrief & Winning Strategies (30 minutes) -_For example:_ +## Repository Contents + +- `./Coach` + - Coach's Guide and related files +- `./Coach/Solutions` + - Solution files with example measurements and techniques for each challenge +- `./Student` + - Student's Challenge Guide +- `./Student/Resources` + - Starter codebase, baseline task, Token Golf specification (Must be packaged up by the coach and provided to students at start of event) - Azure resources that will be consumed by a student implementing the hack's challenges - Azure permissions required by a student to complete the hack's challenges. diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-00.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-00.md index 8ca1a44d71..d14906e4fd 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-00.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-00.md @@ -1,20 +1,76 @@ -# Challenge 00 - <Title of Challenge> - Coach's Guide +# Challenge 00 - Prerequisites & Baseline - Coach's Guide **[Home](./README.md)** - [Next Solution >](./Solution-01.md) ## Notes & Guidance -This is the only section you need to include. +This challenge establishes the measurement baseline that all subsequent challenges compare against. Students must be able to track credit consumption accurately before they can optimize. -Use general non-bulleted text for the beginning of a solution area for this challenge +### Key Concepts to Explain -- Then move into bullets - - And sub-bullets and even - - sub-sub-bullets +**Usage-Based Billing (UBB) Fundamentals:** +- Credit cost = (input tokens × input rate) + (output tokens × output rate) +- Different models have different rates (Sonnet/GPT-4 class vs. Haiku class can be 10x difference) +- VS Code Output panel shows token breakdowns per interaction +- GitHub Copilot usage dashboard shows cumulative spend -Break things apart with more than one bullet list +**Baseline Purpose:** +- Establishes "before" measurement for all optimization techniques +- Students should use their natural workflow—no optimization yet +- Document approach (inline completions, chat frequency, workspace references used) +- This baseline will likely be inefficient—that's intentional -- Like this -- One -- Right -- Here +### Common Blockers + +**UBB Not Enabled:** +- Some organizations may still be on seat-based billing +- Students need admin access or must coordinate with billing admin +- Workaround: Coach can provide sample baseline data if UBB isn't available + +**Token Visibility Issues:** +- VS Code Output panel must be configured to show GitHub Copilot Chat logs +- Some students may not see token counts if using older Copilot extension version +- Solution: Update GitHub Copilot extension to latest version + +**Baseline Task Selection:** +- Task should be non-trivial (10-20 minutes of development) +- Task should be completable in multiple ways (leaves room for optimization) +- Suggested baseline tasks: + - Implement a REST API endpoint with validation and error handling + - Add authentication middleware to an existing service + - Refactor a module to use dependency injection + +### Expected Time + +45 minutes total: +- 15 minutes: Environment setup and UBB verification +- 20 minutes: Complete baseline coding task +- 10 minutes: Document measurements and approach + +### Success Criteria Validation + +Students should demonstrate: +- Screenshot or screen share of VS Code Output panel showing token counts +- Screenshot of GitHub Copilot usage dashboard showing current credit balance +- Completed baseline task code (doesn't need to be perfect) +- Written documentation: total credits consumed, features used, approach taken + +### Hints to Share + +- Don't optimize yet! Use your natural workflow +- Document everything—this is your "before" picture +- If credits seem surprisingly high, that's normal and expected +- Track not just total credits, but which interactions cost the most +- Note: inline completions are typically much cheaper per-interaction than chat/edits + +### Reference Measurements + +Typical baseline measurements for a 15-20 minute coding task: +- Unoptimized: 50-80 credits (using GPT-4 class model, verbose chat, broad references) +- Expected after optimization: 10-20 credits (targeted instructions, efficient model, pinned attachments) + +### Additional Resources for Coach + +- Ensure Resources.zip contains `baseline-task.md` with clear requirements +- Consider providing a reference completion for teams that get stuck +- Have sample token breakdowns ready to share if students can't see theirs diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md index 01d1e30c27..8006c0f7cb 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md @@ -1,20 +1,145 @@ -# Challenge 01 - <Title of Challenge> - Coach's Guide +# Challenge 01 - Context Engineering - Coach's Guide [< Previous Solution](./Solution-00.md) - **[Home](./README.md)** - [Next Solution >](./Solution-02.md) ## Notes & Guidance -This is the only section you need to include. +This challenge teaches students that persistent context has recurring costs. The goal is to minimize always-on overhead while maintaining quality through scoped instructions and precise attachments. -Use general non-bulleted text for the beginning of a solution area for this challenge +### Key Concepts to Explain -- Then move into bullets - - And sub-bullets and even - - sub-sub-bullets +**The Three Types of Context Costs:** -Break things apart with more than one bullet list +1. **Persistent Instructions (recurring cost):** + - `.github/copilot-instructions.md` loads on EVERY interaction + - Example: 1500-token global file = 1500 tokens × every chat/edit call + - Target: keep global instructions under 500-1000 tokens -- Like this -- One -- Right -- Here +2. **GitHub Copilot Skills (conditional cost):** + - Only load when explicitly invoked + - Example: `@workspace /new` only loads creation templates when called + - Best for: task-specific patterns that don't apply to all work + +3. **Attachments (per-call cost):** + - You control exactly what's included each time + - Example: `#file:src/api/routes.ts` only loads when you attach it + - `#Codebase` can pull in thousands of unnecessary tokens + +### Part A: Instruction Scoping Strategy + +**Audit Process:** + +Help students categorize their bloated instructions: + +- **Keep Global (under 500 tokens):** + - Code style preferences that apply universally (e.g., "prefer functional patterns") + - Quality standards (e.g., "always handle errors explicitly") + - Organization-wide conventions + +- **Move to Language-Specific:** + - `.github/copilot-instructions-python.md` for Python-only rules + - `.github/copilot-instructions-typescript.md` for TypeScript-only rules + - These only load when working in that language + +- **Move to Path-Specific:** + - `src/api/.github/copilot-instructions.md` for API-specific patterns + - `tests/.github/copilot-instructions.md` for testing conventions + - These only load when working in that directory + +- **Convert to Skills:** + - Task-specific templates (e.g., "how to write a migration") + - Conditional patterns (e.g., "when adding a new model, do X") + +**Expected Savings:** + +- Before: ~1500 tokens per interaction (global instructions) +- After: ~400 tokens global + ~200 tokens scoped (only when in scope) +- Result: 60-70% reduction in instruction overhead for most interactions + +### Part B: Attachment Precision + +**Common Anti-Pattern:** + +``` +Prompt: "Refactor the authentication logic" +Attachments: #Codebase +``` +This pulls in everything—potentially 50,000+ tokens for a large repo. + +**Optimized Pattern:** + +``` +Prompt: "Refactor the authentication logic" +Attachments: + - #file:src/auth/middleware.ts:1-50 + - #file:src/auth/types.ts + - #file:tests/auth.test.ts +``` +This pulls in exactly what's needed—perhaps 500 tokens. + +**Demonstration Exercise:** + +Have students complete the same refactor twice: +1. With `#Codebase` (record token count from Output panel) +2. With pinned files (record token count) + +Typical results: 10,000+ tokens → 800 tokens (90%+ reduction) + +### Common Blockers + +**Students Don't Know What to Keep Global:** + +Rule of thumb: If a rule only applies to 20% of your codebase, it shouldn't be global. + +**Path-Specific Instructions Not Loading:** + +GitHub Copilot walks up the directory tree looking for `.github/copilot-instructions.md` files. Ensure: +- Directory structure is correct +- File is named exactly `.github/copilot-instructions.md` (not `.github/copilot-instructions-api.md` in the api folder) + +**Can't Measure Token Reduction:** + +- VS Code Output panel (View → Output → "GitHub Copilot Chat") shows token counts +- If not visible, update GitHub Copilot extension to latest version + +### Expected Time + +60 minutes total: +- 20 minutes: Audit and categorize global instructions +- 20 minutes: Restructure into scoped files +- 20 minutes: Test attachment precision and measure savings + +### Success Criteria Validation + +Students should demonstrate: +- Global `.github/copilot-instructions.md` reduced to under 500 tokens +- At least one path-specific or language-specific instruction file created +- Token comparison showing savings from pinned attachments vs. `#Codebase` +- Same baseline task completed with reduced credit cost + +### Hints to Share + +- Start by asking: "Does this rule apply to ALL code I write?" If no, scope it +- Use language-specific files for linting/formatting rules that vary by language +- Use path-specific files for architectural patterns (e.g., API conventions in `src/api/`) +- Pin files when you know exactly what you need; use `#Codebase` only for discovery +- The goal isn't zero instructions—it's right-sized instructions + +### Reference Solutions + +Typical restructuring: + +**Before (1500 tokens global):** +``` +.github/copilot-instructions.md (all rules) +``` + +**After (400 tokens global + scoped):** +``` +.github/copilot-instructions.md (universal rules, ~400 tokens) +.github/copilot-instructions-python.md (Python-specific, ~300 tokens) +.github/copilot-instructions-typescript.md (TypeScript-specific, ~250 tokens) +src/api/.github/copilot-instructions.md (API patterns, ~200 tokens) +``` + +Students working in `src/api/*.ts` now load: 400 + 250 + 200 = 850 tokens (vs. 1500 before) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md index 1ef8ca5035..929d4884e5 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md @@ -1,20 +1,49 @@ -# Challenge 02 - <Title of Challenge> - Coach's Guide +# Challenge 02 - Model Selection & Output Constraints - Coach's Guide [< Previous Solution](./Solution-01.md) - **[Home](./README.md)** - [Next Solution >](./Solution-03.md) ## Notes & Guidance -This is the only section you need to include. +This challenge demonstrates that credit cost depends on both model selection and output volume. A cheaper model with tight constraints often beats an expensive model with verbose output. -Use general non-bulleted text for the beginning of a solution area for this challenge +### Key Concepts to Explain -- Then move into bullets - - And sub-bullets and even - - sub-sub-bullets +**Model Pricing Hierarchy (Approximate):** +- GPT-4o class: ~1x baseline cost +- Claude Sonnet: ~1x baseline cost +- Claude Haiku: ~0.1x baseline cost (10x cheaper) -Break things apart with more than one bullet list +**Output constraints as cost controls:** +- "Output code only" eliminates explanation tokens +- JSON schema constrains response format +- Word limits ("explain in <50 words") cap verbosity +- Structured output prevents rambling -- Like this -- One -- Right -- Here +### Key Data Points to Share + +**Real-world comparison:** +- Regular Agent Mode (Sonnet): ~65 credits for a moderate task +- Custom Agent (Haiku) with "code only" constraint: ~7.6 credits for same task +- Savings: 88% reduction by choosing cheaper model + output constraints + +**When to use each model:** +- Haiku: Boilerplate, refactoring, well-defined tasks +- Sonnet/GPT-4: Complex logic, architecture decisions, debugging novel issues +- Auto mode: Let GitHub Copilot route based on complexity (10% discount for cache-aware routing) + +### Expected Time + +60 minutes: +- 20 minutes: Complete baseline task with 3+ different models +- 20 minutes: Apply output constraints to one model +- 20 minutes: Measure and document findings + +### Success Criteria Validation + +Students should show credit cost comparison table across models and demonstrate measurable savings from output constraints. + +### Hints to Share + +- The fastest model isn't always the cheapest—total credits = input rate + output rate +- If your prompt is 1000 tokens and response is 500 tokens, output constraints save more than model switching +- Auto mode's 10% discount comes from cache-aware routing, but only when natural task boundaries align diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md index 9591196509..9d8bd85284 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md @@ -1,20 +1,41 @@ -# Challenge 03 - <Title of Challenge> - Coach's Guide +# Challenge 03 - Session Configuration (Tools + Cache) - Coach's Guide [< Previous Solution](./Solution-02.md) - **[Home](./README.md)** - [Next Solution >](./Solution-04.md) ## Notes & Guidance -This is the only section you need to include. +This challenge teaches that session configuration affects both recurring costs (MCP tools) and one-time costs (cache invalidation penalties). -Use general non-bulleted text for the beginning of a solution area for this challenge +### Key Concepts to Explain -- Then move into bullets - - And sub-bullets and even - - sub-sub-bullets +**Tool Overhead:** +- Each MCP tool adds 100-500 tokens per agent step +- Tools are advertised to the model even if never invoked +- 10 unused tools × 200 tokens × 20 agent steps = 40,000 extra tokens -Break things apart with more than one bullet list +**Cache Invalidation Triggers:** +- Switching models mid-session (biggest penalty) +- Toggling MCP tools on/off +- Editing `.github/copilot-instructions.md` +- Large context changes (auto-compaction) -- Like this -- One -- Right -- Here +**Engineering Target:** +97-98% cache hit rate is achievable with clean session hygiene. + +### Expected Time + +45 minutes: +- 15 minutes: Audit and prune MCP tools +- 20 minutes: Compare clean vs. messy session +- 10 minutes: Document findings + +### Success Criteria Validation + +Students should show measurable tool overhead savings and demonstrate understanding of cache invalidation impact through comparative measurements. + +### Hints to Share + +- Check VS Code Output panel for tool invocations—if a tool never appears, you don't need it enabled +- Cache hit rate visible in Output panel—look for "cache hit" vs "cache miss" counts +- Switching models mid-session is one of the most expensive cache invalidations +- If you must change configuration, finish your current subtask first to preserve cache value diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md index 90a770fdb3..c21bbb1efe 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md @@ -1,20 +1,44 @@ -# Challenge 04 - <Title of Challenge> - Coach's Guide +# Challenge 04 - Context Window Management - Coach's Guide [< Previous Solution](./Solution-03.md) - **[Home](./README.md)** - [Next Solution >](./Solution-05.md) ## Notes & Guidance -This is the only section you need to include. +This challenge teaches proactive context management vs. reactive recovery. The biggest avoidable cost is not running `/compact` until context rot has already degraded quality. -Use general non-bulleted text for the beginning of a solution area for this challenge +### Key Concepts to Explain -- Then move into bullets - - And sub-bullets and even - - sub-sub-bullets +**Context Rot Timeline:** +- 0-60% capacity: Quality remains high +- 60-70% capacity: First signs of degradation (inconsistencies) +- 70-85% capacity: Noticeable quality loss, forgotten requirements +- 85-100% capacity: Severe degradation, expensive recovery loops -Break things apart with more than one bullet list +**Two Commands, Different Purposes:** +- `/compact`: Summarizes previous work, preserves state, preserves cache (steering wheel) +- `/clear`: Wipes everything, cold cache restart (reset button) -- Like this -- One -- Right -- Here +**Natural Breakpoints for Compaction:** +- Feature complete and tests passing +- Architecture decision made +- Switching to new topic/module +- Before context hits 60% utilization + +### Expected Time + +45 minutes: +- 15 minutes: Observe context rot (Part A) +- 20 minutes: Demonstrate proactive compaction (Part B) +- 10 minutes: Document findings + +### Success Criteria Validation + +Students should demonstrate measurable quality degradation after 70% context utilization and show credit savings from proactive `/compact` vs. letting context rot. + +### Hints to Share + +- Context window utilization visible in VS Code status bar or Output panel +- Run `/compact` before you feel the pain, not after +- Natural breakpoints: "I just finished X, now starting Y"—compact at the transition +- `/compact` preserves cache; `/clear` forces cold restart +- The cost isn't running `/compact` too often—it's running it too late diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md index c320bf9745..03293f6206 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md @@ -1,20 +1,64 @@ -# Challenge 05 - <Title of Challenge> - Coach's Guide +# Challenge 05 - Spec-Driven Development - Coach's Guide -[< Previous Solution](./Solution-04.md) - **[Home](./README.md)** +[< Previous Solution](./Solution-04.md) - **[Home](./README.md)** - [Next Solution >](./Solution-06.md) ## Notes & Guidance -This is the only section you need to include. +This challenge proves that deterministic controls (tests, types, linters) are token controls. When GitHub Copilot has a spec to code against, it closes the loop in one call instead of three model turns of trial-and-error. -Use general non-bulleted text for the beginning of a solution area for this challenge +### Key Concepts to Explain -- Then move into bullets - - And sub-bullets and even - - sub-sub-bullets +**The Feedback Loop Hierarchy (Cost & Latency):** -Break things apart with more than one bullet list +1. **Type errors:** Instant feedback, zero credits +2. **Linter violations:** Seconds, zero credits +3. **Unit tests:** Seconds, zero credits +4. **Agent trial-and-error:** Minutes, high credit cost -- Like this -- One -- Right -- Here +**Spec-First Approach:** +- Write failing tests before implementation (TDD) +- Define types/interfaces that constrain the solution space +- Establish clear acceptance criteria in the prompt +- Let the agent code against the spec + +**Why This Reduces Cost:** +- Tests catch errors deterministically instead of agent discovering through iteration +- Type checkers provide instant feedback vs. agent debugging +- Clear acceptance criteria prevent "did I meet the requirements?" prompting +- The research → plan → implement loop prevents expensive backtracking + +### Expected Time + +60 minutes: +- 25 minutes: Implement feature trial-and-error style (Part A) +- 25 minutes: Implement same feature spec-first (Part B) +- 10 minutes: Compare and document findings + +### Success Criteria Validation + +Students should demonstrate at least 30% credit reduction using spec-first vs. trial-and-error for the same feature complexity. + +### Common Blockers + +**Students Don't Know How to Write Specs:** + +Guide them: +1. Start with types/interfaces (what shape is the solution?) +2. Write failing tests (what behavior must exist?) +3. Document acceptance criteria (when am I done?) + +**Students Skip Research/Plan Phases:** + +Explain: The agent can help write your spec! Ask "what tests should I write for feature X?" before asking "implement feature X." + +### Hints to Share + +- "Write the test first" is both good TDD and good token economics +- Let the agent help write your tests if you provide requirements +- Type errors are free feedback—leverage them before prompting for fixes +- The most expensive code is code you have to regenerate after discovering the approach was wrong +- Research → plan → implement is cheaper than implement → discover wrong → regenerate → recover + +### Key Insight for Students + +The single most leveraged answer to "how do I make my team more efficient with GitHub Copilot" is: give them fast deterministic feedback loops. Tests, types, and linters close loops in zero credits instead of expensive model turns. diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-06.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-06.md new file mode 100644 index 0000000000..3ee6c24ff6 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-06.md @@ -0,0 +1,189 @@ +# Challenge 06 - Token Golf Competition - Coach's Guide + +[< Previous Solution](./Solution-05.md) - **[Home](./README.md)** + +## Notes & Guidance + +Token Golf is the capstone challenge where teams apply all optimization techniques competitively. This is both a validation of learning and a motivating team activity. + +### Coach Pre-Work (CRITICAL) + +**You must complete the Token Golf task yourself before the hack:** + +1. Implement the coding task specified in `/Student/Resources/Challenge06/token-golf-task.md` +2. Use optimization techniques from Challenges 1-5 +3. Record your total credit consumption—this becomes "par" +4. Document your approach: prompt sequence, model choices, techniques used +5. Prepare to share your "par score" at the start of Challenge 06 + +**Setting Par:** + +Your "par score" should represent a well-optimized solution—not perfect, but competent. Aim for: +- Global instructions scoped appropriately (Challenge 01) +- Efficient model selection (Challenge 02) +- Clean session hygiene (Challenge 03) +- Proactive compaction (Challenge 04) +- Spec-first approach (Challenge 05) + +Typical par scores for a moderate complexity task: 15-25 credits (vs. 60-100 unoptimized). + +### Key Concepts to Explain + +**Scorecard Requirements:** + +Teams must document their complete approach, not just final credits. This prevents "got lucky" wins and ensures learning transfer. Required scorecard elements: + +- Total credits consumed (from VS Code Output panel) +- Prompt sequence (what prompts, in what order) +- Models selected for each subtask (e.g., Haiku for boilerplate, Sonnet for complex logic) +- Techniques from previous challenges applied: + - Which instruction scoping strategy (Challenge 01) + - Output constraints used (Challenge 02) + - Tools pruned (Challenge 03) + - Compaction points (Challenge 04) + - Spec-first approach (Challenge 05) +- Any custom techniques or strategies + +**What Counts Toward Score:** + +- All GitHub Copilot interactions: inline completions, chat, edits, workspace queries +- Token costs visible in VS Code Output panel +- From task start to acceptance criteria met (tests pass, docs exist, quality standards met) + +**What Doesn't Count:** + +- Manual typing (zero cost) +- Linters/type checkers/tests running locally (zero cost) +- Time spent (not measured, only credits) + +### Task Design Guidance + +The Token Golf task should: +- Be completable in 45-60 minutes by an experienced developer +- Have clear, measurable acceptance criteria (tests pass, docs exist, etc.) +- Offer multiple solution approaches (so there's no single "right" path) +- Require enough complexity that optimization techniques matter + +**Example Task Structure:** + +```markdown +# Token Golf Task: Build a Rate-Limiting Middleware + +## Functional Requirements +- Implement rate limiting middleware that tracks requests per IP address +- Support configurable limits (requests per minute) +- Return HTTP 429 when limit exceeded +- Clean up expired entries periodically + +## Acceptance Criteria +- All provided unit tests pass +- Middleware handles concurrent requests correctly +- Documentation includes usage examples +- Code passes linting and type checking +- No security vulnerabilities in rate tracking logic + +## Provided Files +- tests/rate-limiter.test.ts (failing tests you must make pass) +- types/middleware.ts (type definitions) +- example-usage.md (what the docs should look like) +``` + +### Competition Format Options + +**Option 1: All Teams Same Task (Standard)** +- Everyone implements the same feature +- Direct comparison of credit costs +- Simplest to judge + +**Option 2: Teams Choose Task (Advanced)** +- Provide 2-3 tasks of similar complexity +- Teams choose which to implement +- Normalizes for skill/interest differences + +**Option 3: Live Leaderboard (High Energy)** +- Teams submit scores as they complete +- Display running leaderboard on screen +- Creates competitive energy + +### Common Blockers + +**Teams Don't Know Where to Start:** + +Hint: Apply the research → plan → implement loop: +1. Research: Read requirements, understand acceptance criteria +2. Plan: Write failing tests, define types, establish spec +3. Implement: Use GitHub Copilot to code against the spec + +**Teams Optimize for Speed, Not Cost:** + +Remind: This is token golf, not speed golf. Taking an extra 2 minutes to write tests first can save 20 credits in trial-and-error. + +**Teams Hit Dead-Ends and Burn Credits Recovering:** + +Encourage `/clear` when stuck—start fresh rather than spending credits digging out of a wrong approach. + +### Expected Time + +60 minutes total: +- 5 minutes: Explain task and rules, announce "par score" +- 45 minutes: Teams implement and measure +- 10 minutes: Debrief and winning strategies + +### Judging Criteria + +**Primary:** Lowest credit cost meeting all acceptance criteria + +**Tiebreakers (in order):** +1. Completion time (earliest submission) +2. Code quality (subjective coach judgment) + +**Disqualifications:** +- Missing acceptance criteria (tests fail, docs missing, linting errors) +- Scorecard not documented (can't verify techniques used) + +### Debrief Discussion Points + +After announcing the winner, discuss: + +**Winning Strategies:** +- What techniques from Challenges 1-5 did the winner apply? +- Where did other teams spend unnecessary credits? +- What would you do differently next time? + +**Key Lessons:** +- "Write the test first" is both good TDD and good token economics +- Cheaper models with tight constraints often beat expensive models with verbose output +- The biggest credit burns are recovery loops—avoid them with upfront specs +- Cache hygiene matters—context rot forces expensive recovery + +### Variations for Future Events + +**Handicap System:** +- Give less experienced teams a credit bonus (e.g., +10 credits) +- Levels the playing field while still rewarding optimization + +**Relay Format:** +- Teams implement different features sequentially +- Each team inherits the codebase from the previous team +- Tests cache management and context handoff strategies + +**Real-World Constraints:** +- Limit model selection (e.g., Haiku only—forces maximum efficiency) +- Introduce mid-task requirement changes (tests cache invalidation handling) + +### Reference Par Scores + +Typical par scores for well-designed tasks: +- Simple task (15-20 min): 10-15 credits +- Moderate task (30-45 min): 15-25 credits +- Complex task (60 min): 25-40 credits + +If student scores are all within 10% of par, the task is well-calibrated. If spread is wide (some 2x par, some under par), the task may have trap paths that burn credits unnecessarily. + +### Post-Event Follow-Up + +Encourage teams to: +- Document their organization's "token golf guidelines" based on learnings +- Share winning strategies internally +- Apply these techniques to real work (measure before/after on production tasks) +- Track team-wide credit spend reduction over next 30 days \ No newline at end of file diff --git a/xxx-GitHubCopilotCostOptimization/README.md b/xxx-GitHubCopilotCostOptimization/README.md index 2cc1b99151..0257b86220 100644 --- a/xxx-GitHubCopilotCostOptimization/README.md +++ b/xxx-GitHubCopilotCostOptimization/README.md @@ -1,40 +1,52 @@ -# What The Hack - GitHubCopilotCostOptimization +# What The Hack - GitHub Copilot Cost Optimization ## Introduction -The IoT Hack of the Century will take you on a whirlwind tour in the world of IoT and how it is being used in the modern world of mineral extraction in exotic locations like the Arctic and the wilds of South Africa. +GitHub Copilot transforms developer productivity, but with usage-based billing (UBB), every token counts. This What The Hack teaches engineering teams how to maximize code quality while minimizing AI credit spend through smart engineering practices. + +You'll learn to control the three cost levers: what enters the context (instructions, attachments, MCP tools), what the model produces (model selection, output constraints), and how efficiently you use the session (cache management, context window hygiene, deterministic feedback loops). By the end, you'll understand that most Copilot cost optimization isn't about restricting usage—it's about engineering better inputs and workflows that help the agent succeed faster. ## Learning Objectives -In this hack you will be solving the common business problem that companies in the mineral extraction industry face and how IoT solutions from Azure are brought to bare +In this hack, you will learn practical techniques to optimize GitHub Copilot usage costs: -1. Provision an IoT Hub -2. Set up an IoT Edge device -3. Bring Azure Sphere to your solution for scale and resiliency +- Reduce persistent instruction overhead through scoped, path-specific configuration files +- Choose appropriate models and apply output constraints to control generation costs +- Manage MCP tool sprawl and understand cache invalidation triggers +- Apply proactive context window management to maintain quality and control costs +- Leverage deterministic feedback loops (tests, linters, type checks) as token controls +- Measure and compare credit spend across different coding workflows ## Challenges -- Challenge 00: **[Prerequisites - Ready, Set, GO!](Student/Challenge-00.md)** - - Prepare your workstation to work with Azure. -- Challenge 01: **[Title of Challenge](Student/Challenge-01.md)** - - Description of challenge -- Challenge 02: **[Title of Challenge](Student/Challenge-02.md)** - - Description of challenge -- Challenge 03: **[Title of Challenge](Student/Challenge-03.md)** - - Description of challenge -- Challenge 04: **[Title of Challenge](Student/Challenge-04.md)** - - Description of challenge -- Challenge 05: **[Title of Challenge](Student/Challenge-05.md)** - - Description of challenge +- Challenge 00: **[Prerequisites & Baseline](Student/Challenge-00.md)** + - Set up the hack environment, confirm UBB tracking is working, and establish your baseline credit spend +- Challenge 01: **[Context Engineering](Student/Challenge-01.md)** + - Audit and restructure global instructions into scoped files, and replace broad references with pinned attachments +- Challenge 02: **[Model Selection & Output Constraints](Student/Challenge-02.md)** + - Compare credit costs across models and reasoning levels, and apply output constraints to reduce token spend +- Challenge 03: **[Session Configuration (Tools + Cache)](Student/Challenge-03.md)** + - Prune unused MCP tools and understand cache invalidation patterns +- Challenge 04: **[Context Window Management](Student/Challenge-04.md)** + - Use /compact proactively to manage growing context windows and avoid context rot +- Challenge 05: **[Spec-Driven Development](Student/Challenge-05.md)** + - Demonstrate that deterministic controls (tests, specs) reduce trial-and-error token burn +- Challenge 06: **[Token Golf Competition](Student/Challenge-06.md)** + - Complete a coding task with the lowest credit spend while meeting all acceptance criteria ## Prerequisites -- Your own Azure subscription with Owner access -- Visual Studio Code -- Azure CLI -- An AVNET X231 device +- GitHub Copilot subscription with usage-based billing (UBB) enabled +- Visual Studio Code with GitHub Copilot extension installed +- Access to GitHub Copilot usage dashboard +- Basic understanding of software development concepts (testing, linting, version control) +- Familiarity with command-line tools and development environments + +## Repository Contents + +- `Student/Resources/` - Starter codebase with intentionally sub-optimal Copilot configuration for teams to optimize +- `Coach/Solutions/` - Reference implementations and measurement data for each challenge ## Contributors -- Jane Q. Public -- Joe T. Muppet +- Andy Huang diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-00.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-00.md index 632f605df9..9b10f20f94 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-00.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-00.md @@ -1,100 +1,55 @@ -# Challenge 00 - Prerequisites - Ready, Set, GO! +# Challenge 00 - Prerequisites & Baseline **[Home](../README.md)** - [Next Challenge >](./Challenge-01.md) -**_This is a template for "Challenge Zero" which focuses on getting prerequisites set up for the hack. The italicized text provides hints & examples of what should or should NOT go in each section._** - -**_We have included links to some common What The Hack pre-reqs in this template. All common prerequisite links go to the WTH-CommonPrerequisites page where there are more details on what each tool's purpose is._** - -**_You should remove any common pre-reqs that are not required for your hack. Then add additional pre-reqs that are required for your hack in the Description section below._** - -**_You should remove all italicized & sample text in this template and replace with your content._** - ## Introduction -Thank you for participating in the GitHubCopilotCostOptimization What The Hack. Before you can hack, you will need to set up some prerequisites. - -## Common Prerequisites - -We have compiled a list of common tools and software that will come in handy to complete most What The Hack Azure-based hacks! +Thank you for participating in the GitHub Copilot Cost Optimization What The Hack. Before you begin optimizing, you need to set up your environment to measure GitHub Copilot usage costs accurately. This challenge establishes your baseline—the "before" measurement that all subsequent challenges will compare against. -You might not need all of them for the hack you are participating in. However, if you work with Azure on a regular basis, these are all things you should consider having in your toolbox. - -<!-- If you are editing this template manually, be aware that these links are only designed to work if this Markdown file is in the /xxx-HackName/Student/ folder of your hack. --> - -- [Azure Subscription](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-subscription) -- [Windows Subsystem for Linux](../../000-HowToHack/WTH-Common-Prerequisites.md#windows-subsystem-for-linux) -- [Managing Cloud Resources](../../000-HowToHack/WTH-Common-Prerequisites.md#managing-cloud-resources) - - [Azure Portal](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-portal) - - [Azure CLI](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-cli) - - [Note for Windows Users](../../000-HowToHack/WTH-Common-Prerequisites.md#note-for-windows-users) - - [Azure PowerShell CmdLets](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-powershell-cmdlets) - - [Azure Cloud Shell](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-cloud-shell) -- [Visual Studio Code](../../000-HowToHack/WTH-Common-Prerequisites.md#visual-studio-code) - - [VS Code plugin for ARM Templates](../../000-HowToHack/WTH-Common-Prerequisites.md#visual-studio-code-plugins-for-arm-templates) -- [Azure Storage Explorer](../../000-HowToHack/WTH-Common-Prerequisites.md#azure-storage-explorer) +Understanding where credits go is essential to optimization. In this challenge, you'll confirm that usage-based billing (UBB) is active, learn how to read token breakdowns in VS Code, and complete a baseline coding task to capture your starting credit spend. ## Description -_This section should clearly state any additional prerequisite tools that need to be installed or set up in the Azure environment that the student will hack in._ - -_While ordered lists are generally not welcome in What The Hack challenge descriptions, you can use one here in Challenge Zero IF and only IF the steps you are asking the student to perform are not core to the learning objectives of the hack._ - -_For example, if the hack is on IoT Devices and you want the student to deploy an ARM/Bicep template that sets up the environment they will hack in without them needing to understand how ARM/Bicep templates work, you can provide step-by-step instructions on how to deploy the ARM/Bicep template._ - -_Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack. You should leave the sample text below in that refers to the Resources.zip file._ +Your coach will provide you with a Resources.zip file that contains a starter codebase for this hack. The codebase is intentionally configured with sub-optimal GitHub Copilot settings—you'll be optimizing these in later challenges. -**\*NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resources.zip file provided by the coach.\* +Please complete the following setup steps: -**\*NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.\* +1. Extract the Resources.zip file to your local workstation +2. Open Visual Studio Code and install/update the GitHub Copilot extension to the latest version +3. Verify your GitHub Copilot subscription has usage-based billing (UBB) enabled by checking your billing settings +4. Enable token usage visibility in VS Code: + - Open the Output panel (View > Output) + - Select "GitHub Copilot Chat" from the dropdown + - Verify you can see token counts and credit usage per interaction +5. Confirm you can access your GitHub Copilot usage dashboard to view cumulative credit spend +6. Open the starter codebase in VS Code and familiarize yourself with its structure -_Sample challenge zero text for the IoT Hack Of The Century:_ +### Baseline Measurement -Now that you have the common pre-requisites installed on your workstation, there are prerequisites specifc to this hack. +Once your environment is configured, complete the baseline coding task: -Your coach will provide you with a Resources.zip file that contains resources you will need to complete the hack. If you plan to work locally, you should unpack it on your workstation. If you plan to use the Azure Cloud Shell, you should upload it to the Cloud Shell and unpack it there. +1. Locate the `baseline-task.md` file in the `/Challenge00/` folder of the Resources.zip +2. Complete the coding task described using GitHub Copilot Chat in your normal working style (don't optimize yet!) +3. Record the total credits consumed for this task from the VS Code Output panel +4. Document your approach: which features you used (inline completions, chat, edits, workspace references) +5. Save your baseline measurements—you'll compare all future challenges against this -Please install these additional tools: - -- [Azure IoT Tools](https://marketplace.visualstudio.com/items?itemName=vsciot-vscode.azure-iot-tools) extension for Visual Studio Code -- .NET SDK 6.0 or later installed on your development machine. This can be downloaded from [here](https://www.microsoft.com/net/download/all) for multiple platforms. - -In the `/Challenge00/` folder of the Resources.zip file, you will find an ARM template, `setupIoTEnvironment.json` that sets up the initial hack environment in Azure you will work with in subsequent challenges. - -Please deploy the template by running the following Azure CLI commands from the location of the template file: -``` -az group create --name myIoT-rg --location eastus -az group deployment create -g myIoT-rg --name HackEnvironment -f setupIoTEnvironment.json -``` +This baseline represents your "before" state. In subsequent challenges, you'll apply optimization techniques and measure the credit reduction compared to this baseline. ## Success Criteria -_Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach._ - -_The success criteria should not be a list of instructions._ - -_Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."_ - -_Sample success criteria for the IoT prerequisites challenge:_ - To complete this challenge successfully, you should be able to: -- Verify that you have a bash shell with the Azure CLI available. -- Verify that the ARM template has deployed the following resources in Azure: - - Azure IoT Hub - - Virtual Network - - Jumpbox VM +- Verify that usage-based billing (UBB) is active on your GitHub Copilot subscription +- Demonstrate that the VS Code Output panel shows token breakdowns for GitHub Copilot interactions +- Show that you can access the GitHub Copilot usage dashboard and view your current credit consumption +- Verify that the starter codebase from Resources.zip is open in VS Code +- Demonstrate that you have completed the baseline coding task and recorded the credit spend +- Show your documented baseline measurements including total credits and approach used ## Learning Resources -_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ - -_Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario._ - -**\*Note:** Use descriptive text for each link instead of just URLs.\* - -_Sample IoT resource links:_ - -- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) -- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) -- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) +- [GitHub Copilot Usage-Based Billing Overview](https://docs.github.com/en/copilot/about-github-copilot/what-is-github-copilot#pricing-for-github-copilot) +- [Understanding GitHub Copilot Tokens and Credits](https://docs.github.com/en/copilot) +- [Visual Studio Code Output Panel Documentation](https://code.visualstudio.com/docs/getstarted/userinterface#_output-panel) +- [GitHub Copilot Extension for VS Code](https://marketplace.visualstudio.com/items?itemName=GitHub.copilot) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md index fcf81ed831..8cd541f642 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md @@ -1,53 +1,75 @@ -# Challenge 01 - <Title of Challenge> +# Challenge 01 - Context Engineering [< Previous Challenge](./Challenge-00.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-02.md) -***This is a template for a single challenge. The italicized text provides hints & examples of what should or should NOT go in each section. You should remove all italicized & sample text and replace with your content.*** +## Introduction -## Pre-requisites (Optional) +Every token sent to GitHub Copilot has a cost. Context that persists across every interaction—like global `.github/copilot-instructions.md` files—creates recurring costs that compound quickly. Meanwhile, broad workspace references like `#Codebase` pull in unnecessary files, adding tokens you don't need. -*Your hack's "Challenge 0" should cover pre-requisites for the entire hack, and thus this section is optional and may be omitted. If you wish to spell out specific previous challenges that must be completed before starting this challenge, you may do so here.* +In this challenge, you'll learn to engineer your context precisely. You'll audit an over-stuffed global instructions file, restructure it into scoped path-specific files, and replace broad references with pinned attachments. The goal: reduce the base cost of every Copilot interaction while maintaining quality. -## Introduction +## Description -*This section should provide an overview of the technologies or tasks that will be needed to complete the this challenge. This includes the technical context for the challenge, as well as any new "lessons" the attendees should learn before completing the challenge.* +The starter codebase includes an intentionally bloated `.github/copilot-instructions.md` file (~1500 tokens) that loads on every GitHub Copilot interaction. Your task is to optimize the context architecture through two experiments. -*Optionally, the coach or event host is encouraged to present a mini-lesson (with a PPT or video) to set up the context & introduction to each challenge. A summary of the content of that mini-lesson is a good candidate for this Introduction section* +### Part A: Instruction Scoping -*For example:* +Audit the global instructions file and identify rules that: -When setting up an IoT device, it is important to understand how 'thingamajigs' work. Thingamajigs are a key part of every IoT device and ensure they are able to communicate properly with edge servers. Thingamajigs require IP addresses to be assigned to them by a server and thus must have unique MAC addresses. In this challenge, you will get hands on with a thingamajig and learn how one is configured. +- Only apply to specific file types or directories +- Are redundant with existing linters, type checkers, or code standards +- Could be converted to GitHub Copilot Skills that activate conditionally +- Genuinely need to be global (keep these minimal) -## Description +Restructure your instructions: -*This section should clearly state the goals of the challenge and any high-level instructions you want the students to follow. You may provide a list of specifications required to meet the goals. If this is more than 2-3 paragraphs, it is likely you are not doing it right.* +- Keep only universal rules (target: under 500 tokens) in the global `.github/copilot-instructions.md` +- Move language-specific rules to `.github/copilot-instructions-LANGUAGE.md` files (e.g., `copilot-instructions-python.md`) +- Move directory-specific rules to path-scoped instruction files (e.g., `src/api/.github/copilot-instructions.md`) +- Convert task-specific patterns to GitHub Copilot Skills where appropriate -***NOTE:** Do NOT use ordered lists as that is an indicator of 'step-by-step' instructions. Instead, use bullet lists to list out goals and/or specifications.* +### Part B: Attachment Precision -***NOTE:** You may use Markdown sub-headers to organize key sections of your challenge description.* +The starter codebase may include prompts that reference `#Codebase` or other broad workspace selectors. Identify one coding task where you can: -*Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack.* +- Replace a broad `#Codebase` reference with specific pinned files/line ranges +- Demonstrate the token difference between the two approaches +- Verify the output quality remains equivalent -***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* +### Measurement -***NOTE:** As an exception, you may provide a GitHub 'raw' link to an individual file such as a PDF or Office document, so long as it does not open the contents of the file in the What The Hack repo on the GitHub website.* +Complete the same coding task from Challenge 00 (baseline) three times: -***NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.* +- Attempt 1: Using the original bloated global instructions (~1500 tokens) +- Attempt 2: Using your optimized instruction architecture +- Attempt 3: Using optimized instructions + pinned attachments instead of broad references -*Sample challenge text for the IoT Hack Of The Century:* +Record credits consumed for each attempt and calculate the reduction percentage. -In this challenge, you will properly configure the thingamajig for your IoT device so that it can communicate with the mother ship. +## Success Criteria -You can find a sample `thingamajig.config` file in the `/ChallengeXX` folder of the Resources.zip file provided by your coach. This is a good starting reference, but you will need to discover how to set exact settings. +To complete this challenge successfully, you should be able to: -Please configure the thingamajig with the following specifications: -- Use dynamic IP addresses -- Only trust the following whitelisted servers: "mothership", "IoTQueenBee" -- Deny access to "IoTProxyShip" +- Demonstrate that your restructured global `.github/copilot-instructions.md` is under 500 tokens +- Show path-specific or language-specific instruction files you created with rules moved from the global file +- Verify that at least one task-specific pattern has been converted to a GitHub Copilot Skill +- Show token count comparison between using `#Codebase` vs. pinned file attachments for a specific task +- Demonstrate credit reduction across three attempts of the baseline coding task +- Verify that code quality remained equivalent across all three attempts -You can view an architectural diagram of an IoT thingamajig here: [Thingamajig.PDF](/Student/Resources/Architecture.PDF?raw=true). +## Learning Resources -## Success Criteria +- [GitHub Copilot Instructions Documentation](https://docs.github.com/en/copilot/customizing-copilot/adding-custom-instructions-for-github-copilot) +- [GitHub Copilot Skills Overview](https://docs.github.com/en/copilot/using-github-copilot/using-github-copilot-skills) +- [Understanding Context Windows in Large Language Models](https://www.anthropic.com/index/prompting-long-context) + +## Tips + +- Persistent instructions are recurring costs—they load on every call +- Skills are conditional costs—they only load when invoked +- Attachments are per-call costs—you control exactly what's included +- The engineering target: keep always-on global instructions under 1000 tokens +- Scoped instructions should be discoverable: if a rule only applies to `/api`, put the instruction file in `/api/.github/` *Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach.* diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md index 459fb175d5..72ca4e1c35 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md @@ -1,32 +1,77 @@ -# Challenge 02 - <Title of Challenge> +# Challenge 02 - Model Selection & Output Constraints [< Previous Challenge](./Challenge-01.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-03.md) -***This is a template for a single challenge. The italicized text provides hints & examples of what should or should NOT go in each section. You should remove all italicized & sample text and replace with your content.*** +## Introduction -## Pre-requisites (Optional) +Not all tasks need the most powerful model. A cheaper model with tight output constraints can often outperform an expensive model that produces verbose responses. In this challenge, you'll learn to match models to task complexity and apply output constraints that reduce token generation without sacrificing quality. -*Your hack's "Challenge 0" should cover pre-requisites for the entire hack, and thus this section is optional and may be omitted. If you wish to spell out specific previous challenges that must be completed before starting this challenge, you may do so here.* +The key insight: credit cost = (input tokens × input rate) + (output tokens × output rate). While you control input through context engineering, output constraints are your lever for controlling what the model generates. -## Introduction +## Description -*This section should provide an overview of the technologies or tasks that will be needed to complete the this challenge. This includes the technical context for the challenge, as well as any new "lessons" the attendees should learn before completing the challenge.* +Complete the same coding task from your baseline using different GitHub Copilot models and configurations. Your goal is to understand the cost-quality tradeoff and discover when cheaper models with constraints beat expensive models without them. -*Optionally, the coach or event host is encouraged to present a mini-lesson (with a PPT or video) to set up the context & introduction to each challenge. A summary of the content of that mini-lesson is a good candidate for this Introduction section* +### Part A: Model Comparison -*For example:* +Complete your baseline coding task using each available model/reasoning level combination: -When setting up an IoT device, it is important to understand how 'thingamajigs' work. Thingamajigs are a key part of every IoT device and ensure they are able to communicate properly with edge servers. Thingamajigs require IP addresses to be assigned to them by a server and thus must have unique MAC addresses. In this challenge, you will get hands on with a thingamajig and learn how one is configured. +- GPT-4o (standard agent mode) +- Claude Sonnet (standard agent mode) +- Claude Haiku (if available via custom agent) +- Any other models available in your GitHub Copilot configuration -## Description +For each model: + +- Record total credits consumed +- Record output quality (does it meet acceptance criteria?) +- Record number of iterations needed to reach a working solution +- Note the model's response verbosity (tokens generated) + +### Part B: Output Constraints + +Choose one model from Part A and complete the same task multiple times with different output constraints: + +- No constraints (baseline) +- "Output code only, minimal explanation" +- Structured output (e.g., JSON schema for configuration, specific code format) +- Tight word limits for explanations ("explain in <50 words") + +Measure how output constraints affect both token count and credit cost. + +### Part C: Auto Mode Exploration -*This section should clearly state the goals of the challenge and any high-level instructions you want the students to follow. You may provide a list of specifications required to meet the goals. If this is more than 2-3 paragraphs, it is likely you are not doing it right.* +If available, use GitHub Copilot's Auto mode (task-aware routing with cache-aware model selection) to complete the same task: -***NOTE:** Do NOT use ordered lists as that is an indicator of 'step-by-step' instructions. Instead, use bullet lists to list out goals and/or specifications.* +- Observe which models Auto mode selects for different subtasks +- Note when Auto mode chooses to leverage cache vs. switch models +- Compare total credit cost vs. manually selecting a single model +- Understand the 10% discount Auto mode provides for cache-friendly routing -***NOTE:** You may use Markdown sub-headers to organize key sections of your challenge description.* +## Success Criteria + +To complete this challenge successfully, you should be able to: + +- Demonstrate completion of the baseline task using at least three different models +- Show measured credit costs for each model with identical input conditions +- Verify that output quality met acceptance criteria for each model tested +- Demonstrate credit cost reduction from applying output constraints to at least one model +- Show comparative data proving that a cheaper model with constraints can beat an expensive model without constraints on total credit cost +- Explain when Auto mode provides value vs. manual model selection + +## Learning Resources + +- [GitHub Copilot Model Selection Guide](https://docs.github.com/en/copilot) +- [Prompt Engineering: Output Formatting Techniques](https://www.promptingguide.ai/) +- [Understanding Model Pricing and Token Rates](https://docs.github.com/en/copilot/about-github-copilot) + +## Tips -*Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack.* +- Input tokens are cheaper than output tokens for most models +- Verbose explanations cost credits—request code-only output when you don't need narration +- Haiku-class models can be 85-90% cheaper than Sonnet/GPT-4 class models +- Auto mode's 10% discount comes from cache-aware routing, but only when task boundaries align with cache boundaries +- The best model isn't always the smartest one—it's the one that solves your problem at the lowest cost ***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md index 88656873ba..a4b1754c4f 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md @@ -1,32 +1,90 @@ -# Challenge 03 - <Title of Challenge> +# Challenge 03 - Session Configuration (Tools + Cache) [< Previous Challenge](./Challenge-02.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-04.md) -***This is a template for a single challenge. The italicized text provides hints & examples of what should or should NOT go in each section. You should remove all italicized & sample text and replace with your content.*** +## Introduction -## Pre-requisites (Optional) +Every MCP tool you enable adds 100-500 tokens per agent loop step. A session with 10 unused tools can burn thousands of extra tokens before you've written a line of code. Meanwhile, cache invalidation—triggered by switching models, toggling MCP servers, or editing system prompts mid-session—wipes your cache and forces a costly cold restart. -*Your hack's "Challenge 0" should cover pre-requisites for the entire hack, and thus this section is optional and may be omitted. If you wish to spell out specific previous challenges that must be completed before starting this challenge, you may do so here.* +In this challenge, you'll learn to configure lean sessions and maintain high cache hit rates. The engineering target is 97-98% cache efficiency. -## Introduction +## Description -*This section should provide an overview of the technologies or tasks that will be needed to complete the this challenge. This includes the technical context for the challenge, as well as any new "lessons" the attendees should learn before completing the challenge.* +This challenge has two parts: tool sprawl management and cache invalidation awareness. Both directly impact your per-session costs. -*Optionally, the coach or event host is encouraged to present a mini-lesson (with a PPT or video) to set up the context & introduction to each challenge. A summary of the content of that mini-lesson is a good candidate for this Introduction section* +### Part A: Tool Sprawl Audit -*For example:* +The starter codebase may have multiple MCP tools or GitHub Copilot extensions enabled. Your task: -When setting up an IoT device, it is important to understand how 'thingamajigs' work. Thingamajigs are a key part of every IoT device and ensure they are able to communicate properly with edge servers. Thingamajigs require IP addresses to be assigned to them by a server and thus must have unique MAC addresses. In this challenge, you will get hands on with a thingamajig and learn how one is configured. +- List all currently enabled MCP tools and extensions in your GitHub Copilot configuration +- Complete your baseline coding task with all tools enabled, recording token counts and credits +- Identify which tools were actually invoked during the task (check VS Code Output panel for tool calls) +- Disable any tools that weren't used +- Repeat the baseline task with your pruned tool configuration +- Measure credit savings from reducing tool overhead -## Description +Each tool adds token overhead to every agent step, even if never used. The overhead includes: + +- Tool name and description (recurring cost) +- Tool parameter schemas (recurring cost) +- Tool availability announcements (recurring cost) + +### Part B: Cache Invalidation Experiment + +Complete the same refactor task twice under different session conditions: + +**Clean Session:** +- Start a fresh VS Code session +- Configure your chosen model and tool set +- Complete the entire refactor without changing any configuration +- Record total credits and observe cache hit rate in Output panel + +**Messy Session:** +- Start a fresh VS Code session +- Begin the refactor +- Midway through, switch to a different model +- Then toggle an MCP server off and back on +- Then edit your `.github/copilot-instructions.md` file +- Complete the refactor +- Record total credits and observe cache hit rate + +Compare the two approaches. Each configuration change invalidates the cache and triggers a cold restart penalty. -*This section should clearly state the goals of the challenge and any high-level instructions you want the students to follow. You may provide a list of specifications required to meet the goals. If this is more than 2-3 paragraphs, it is likely you are not doing it right.* +### Cache Invalidation Triggers -***NOTE:** Do NOT use ordered lists as that is an indicator of 'step-by-step' instructions. Instead, use bullet lists to list out goals and/or specifications.* +Document your understanding of what invalidates GitHub Copilot's cache: -***NOTE:** You may use Markdown sub-headers to organize key sections of your challenge description.* +- Switching models mid-session +- Changing system instructions (editing copilot-instructions.md) +- Toggling MCP tools or extensions +- Switching between Agent mode and Chat mode +- Large context window changes (auto-compaction) + +## Success Criteria + +To complete this challenge successfully, you should be able to: + +- Show a list of all MCP tools enabled before and after your audit +- Demonstrate credit savings from disabling unused tools on the baseline task +- Verify which tools were actually invoked during your task (via VS Code Output panel logs) +- Show comparative credit costs between clean session and messy session for the same refactor +- Demonstrate measurable cache hit rate difference between the two session approaches +- Explain at least three triggers that invalidate GitHub Copilot's cache +- Achieve 95%+ cache hit rate on a multi-turn coding task + +## Learning Resources + +- [Model Context Protocol (MCP) Overview](https://modelcontextprotocol.io/) +- [GitHub Copilot Extension Management](https://docs.github.com/en/copilot) +- [Understanding LLM Caching Strategies](https://www.anthropic.com/index/prompt-caching) + +## Tips -*Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack.* +- Each MCP tool costs tokens even when never invoked—they're advertised to the model at every step +- Cache hit rates above 97-98% are achievable with clean session hygiene +- Switching models mid-session is one of the most expensive cache invalidations +- Auto mode routes along cache boundaries to minimize invalidation +- If you must change configuration mid-task, finish your current subtask first to preserve cache value ***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md index a032304040..3206c043aa 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md @@ -1,32 +1,85 @@ -# Challenge 04 - <Title of Challenge> +# Challenge 04 - Context Window Management [< Previous Challenge](./Challenge-03.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-05.md) -***This is a template for a single challenge. The italicized text provides hints & examples of what should or should NOT go in each section. You should remove all italicized & sample text and replace with your content.*** +## Introduction -## Pre-requisites (Optional) +Context windows grow with every interaction. As your session accumulates messages, attachments, and generated code, the context window fills. Beyond 60-70% utilization, quality degrades—responses become less accurate, the model "forgets" earlier decisions, and credits burn faster as you pay to transmit bloated context. -*Your hack's "Challenge 0" should cover pre-requisites for the entire hack, and thus this section is optional and may be omitted. If you wish to spell out specific previous challenges that must be completed before starting this challenge, you may do so here.* +In this challenge, you'll learn when and how to use `/compact` (the steering wheel) vs. `/clear` (the reset button). The biggest avoidable cost isn't running `/compact` too often—it's running it too late, after context rot has already degraded quality and forced expensive recovery loops. -## Introduction +## Description -*This section should provide an overview of the technologies or tasks that will be needed to complete the this challenge. This includes the technical context for the challenge, as well as any new "lessons" the attendees should learn before completing the challenge.* +Complete a multi-turn coding task designed to intentionally grow your context window past 60-70% utilization. You'll compare two approaches: proactive compaction vs. reactive recovery. -*Optionally, the coach or event host is encouraged to present a mini-lesson (with a PPT or video) to set up the context & introduction to each challenge. A summary of the content of that mini-lesson is a good candidate for this Introduction section* +### Part A: Context Rot Observation -*For example:* +Start a coding task that involves multiple related features or refactors. Intentionally: -When setting up an IoT device, it is important to understand how 'thingamajigs' work. Thingamajigs are a key part of every IoT device and ensure they are able to communicate properly with edge servers. Thingamajigs require IP addresses to be assigned to them by a server and thus must have unique MAC addresses. In this challenge, you will get hands on with a thingamajig and learn how one is configured. +- Add numerous file attachments +- Request verbose explanations +- Include implementation details in chat responses +- Allow the context window to grow without intervention -## Description +Monitor context window utilization (visible in VS Code status bar or Output panel). Once you reach 70-80% capacity: + +- Observe quality degradation (inconsistencies, forgotten requirements, repeated questions) +- Record credits consumed to reach this point +- Note any incorrect outputs or rework needed + +### Part B: Proactive Compaction + +Restart the same multi-turn task using proactive `/compact`: + +- Use `/compact` at natural breakpoints (after completing a feature, before switching topics) +- Target: keep context window below 60% utilization throughout +- Monitor how compaction summarizes previous work while preserving state +- Compare credits consumed vs. Part A +- Compare output quality vs. Part A + +### Part C: Emergency Reset + +Demonstrate when `/clear` is appropriate: + +- Start a task where you realize mid-way that your approach is fundamentally wrong +- Use `/clear` to wipe context and start fresh with corrected approach +- Understand the cold cache penalty from `/clear` vs. preserved cache with `/compact` +- Measure the credit cost difference -*This section should clearly state the goals of the challenge and any high-level instructions you want the students to follow. You may provide a list of specifications required to meet the goals. If this is more than 2-3 paragraphs, it is likely you are not doing it right.* +### Context Window Hygiene Rules -***NOTE:** Do NOT use ordered lists as that is an indicator of 'step-by-step' instructions. Instead, use bullet lists to list out goals and/or specifications.* +Develop and document your team's rules for context management: -***NOTE:** You may use Markdown sub-headers to organize key sections of your challenge description.* +- At what context utilization percentage do you run `/compact`? +- What are "natural breakpoints" for your workflow (feature completion, test passing, architecture decision)? +- When is `/clear` better than `/compact` (fundamental direction change, context poisoning)? +- How do you balance cache preservation vs. context hygiene? + +## Success Criteria + +To complete this challenge successfully, you should be able to: + +- Demonstrate observable quality degradation when context window exceeds 70% utilization +- Show credit cost comparison between no-compaction (Part A) and proactive compaction (Part B) approaches +- Verify that proactive `/compact` maintained output quality throughout the multi-turn task +- Demonstrate appropriate use of `/clear` when the context becomes fundamentally misaligned +- Explain the difference in cache impact between `/compact` (preserves cache) and `/clear` (cold restart) +- Document your team's context management rules with specific utilization thresholds + +## Learning Resources + +- [Understanding Context Windows and Token Limits](https://www.anthropic.com/index/prompting-long-context) +- [GitHub Copilot Chat Commands Documentation](https://docs.github.com/en/copilot/using-github-copilot/using-github-copilot-chat) +- [Managing Long Conversations with AI Assistants](https://www.promptingguide.ai/) + +## Tips -*Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack.* +- Context rot starts around 60-70% window utilization—don't wait until 90% +- `/compact` is the steering wheel (summarize, preserve state)—use it proactively +- `/clear` is the reset button (wipe everything)—use it when direction changes +- Natural breakpoints: feature complete, tests passing, architecture decision made +- The cost isn't running `/compact`—it's NOT running `/compact` until quality has already degraded +- Compact before you feel the pain, not after ***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index 027fffe5bf..51a1b5dab0 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -1,6 +1,110 @@ -# Challenge 05 - <Title of Challenge> +# Challenge 05 - Spec-Driven Development -[< Previous Challenge](./Challenge-04.md) - **[Home](../README.md)** +[< Previous Challenge](./Challenge-04.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-06.md) + +## Introduction + +Deterministic controls—tests, linters, type checks, and security scans—are token controls. When GitHub Copilot has a spec to code against and a fast feedback loop to verify correctness, it closes the loop in one tool call instead of three model turns of trial-and-error. Every time the agent "gambles" and discovers a mistake through iteration, you pay for discovery and recovery. + +In this challenge, you'll demonstrate that spec-first development isn't just good engineering—it's cost optimization. + +## Description + +You'll implement the same feature twice: once with no spec (trial-and-error), and once with spec-first (deterministic feedback). Compare credit spend and output correctness between the two approaches. + +### Part A: Trial-and-Error Development + +Implement a moderately complex feature using only a vague prompt: + +- Provide GitHub Copilot with a high-level goal (e.g., "add user authentication") +- Do NOT provide tests, types, interfaces, or acceptance criteria +- Do NOT establish linting or type-checking as part of your workflow +- Let the agent explore, make mistakes, and iterate + +Observe and record: + +- How many retry loops occur (agent generates code, you test, it fails, agent fixes) +- Total credits consumed +- Time spent on discovery (agent asking clarifying questions) +- Time spent on recovery (fixing incorrect implementations) +- Final code quality + +### Part B: Spec-First Development + +Implement the same feature using spec-first approach: + +**Before prompting GitHub Copilot, create:** +- Type definitions or interfaces that define the shape of your solution +- Test cases that specify expected behavior (these can fail initially—TDD style) +- Clear acceptance criteria in your prompt or attached specification file +- Enable linters and type checkers in your workflow + +**Then prompt GitHub Copilot with:** +- A link to your type definitions/interfaces +- A link to your failing tests +- Clear acceptance criteria +- Instruction: "Implement this feature to make these tests pass" + +Observe and record: + +- How many iterations needed (should be significantly fewer) +- Total credits consumed +- Whether the agent closed the loop in one pass vs. multiple retries +- Final code quality + +### The Feedback Loop Hierarchy + +Rank feedback mechanisms by cost and latency: + +- **Fastest/Cheapest:** Type errors (instant feedback, zero credit cost) +- **Fast/Cheap:** Linter violations (seconds, zero credit cost) +- **Medium:** Unit tests (seconds, zero credit cost) +- **Slow/Expensive:** Agent trial-and-error (minutes, high credit cost) + +### Key Concepts + +Document your understanding of how deterministic controls reduce token spend: + +- When tests catch errors deterministically, the agent doesn't spend turns discovering the error through iteration +- Type checkers provide instant feedback loops (zero credits) vs. agent debugging (high credits) +- The research → plan → implement loop: sessions that skip research/planning burn tokens regenerating context after the first wrong turn +- CI signals (test pass/fail, lint pass/fail, security scan results) close loops in one tool call instead of three model turns + +## Success Criteria + +To complete this challenge successfully, you should be able to: + +- Demonstrate completion of a feature using trial-and-error (Part A) and spec-first (Part B) approaches +- Show measured credit costs for both approaches with the same feature complexity +- Verify that spec-first approach required fewer retry loops than trial-and-error +- Demonstrate at least 30% credit reduction using spec-first vs. trial-and-error +- Show that spec-first output met acceptance criteria with fewer iterations +- Explain how at least three deterministic controls (tests, types, linters) act as token controls +- Document your feedback loop hierarchy ranking mechanisms by speed and cost + +## Learning Resources + +- [Test-Driven Development Fundamentals](https://martinfowler.com/bliki/TestDrivenDevelopment.html) +- [Type Systems as Documentation](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html) +- [The Cost of Rework in Software Development](https://martinfowler.com/articles/is-quality-worth-cost.html) +- [GitHub Copilot and Test-Driven Development](https://docs.github.com/en/copilot) + +## Tips + +- "Write the test first" is both good TDD and good token economics +- Type errors are free feedback—leverage them before asking the agent +- Linters catch mistakes at zero credit cost—run them before prompting for fixes +- The agent can write your tests if you provide the spec, then implement against those tests +- Research → plan → implement is cheaper than implement → discover mistake → regenerate → recover +- The single most leveraged answer to "how do I make devs more efficient with Copilot" is: give them fast deterministic feedback loops + +## Advanced Challenges + +Too comfortable? Try these: + +- Implement pre-commit hooks that run tests/linters and provide feedback before GitHub Copilot generates fixes +- Create a CI pipeline that provides GitHub Copilot with test results as context for fixing failures +- Measure the credit cost difference between "fix this bug" (vague) vs. "fix this bug: test X fails with error Y" (specific) ***This is a template for a single challenge. The italicized text provides hints & examples of what should or should NOT go in each section. You should remove all italicized & sample text and replace with your content.*** diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-06.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-06.md new file mode 100644 index 0000000000..f9f1772991 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-06.md @@ -0,0 +1,81 @@ +# Challenge 06 - Token Golf Competition 🏌️ + +[< Previous Challenge](./Challenge-05.md) - **[Home](../README.md)** + +## Introduction + +Token golf is the art of achieving high-quality code output with minimal credit spend. In this final challenge, teams compete to complete the same coding task with the lowest credit consumption while meeting all acceptance criteria. This is where you apply everything you've learned: context engineering, model selection, session hygiene, and spec-driven development. + +Your coach has already completed this task and established a "par" score—the credit cost of a well-optimized solution. Can you beat par? + +## Description + +All teams will receive the same coding task with defined acceptance criteria. The task includes: + +- Functional requirements that must be implemented +- Tests that must pass +- Documentation that must exist +- Code quality standards that must be met + +### Competition Rules + +Your team must: + +- Complete all functional requirements described in the task specification (found in the `/Challenge06/` folder of Resources.zip) +- Ensure all provided tests pass +- Include required documentation +- Meet code quality standards (no linting errors, proper typing where applicable) +- Document your complete approach in a "scorecard" that includes: + - Total credits consumed + - Prompt sequence used + - Model(s) selected and reasoning levels + - Optimization techniques applied from Challenges 1-5 + - Any custom techniques or strategies + +### Measurement + +Track every interaction with GitHub Copilot throughout the challenge: + +- Inline completions credit cost +- Chat interactions credit cost +- Edit commands credit cost +- Any workspace or codebase references +- Total cumulative credits for the complete task + +The team with the lowest total credit score that meets all acceptance criteria wins. In case of a tie, the team that completes first breaks the tie. + +### Strategic Considerations + +Consider applying these techniques from previous challenges: + +- Use scoped instructions (Challenge 01) to avoid loading global context unnecessarily +- Select the most efficient model for each subtask (Challenge 02) +- Disable any MCP tools you won't need (Challenge 03) +- Use `/compact` at strategic breakpoints if needed (Challenge 04) +- Start with the spec: write tests first to create deterministic feedback loops (Challenge 05) + +## Success Criteria + +To complete this challenge successfully, you should be able to: + +- Verify that all functional requirements from the task specification are implemented +- Demonstrate that all provided tests pass +- Show that required documentation exists and meets standards +- Verify that code meets quality standards (no linting errors, proper types) +- Show your documented scorecard with total credits consumed and techniques applied +- Demonstrate that your solution meets or beats the coach's "par" score (bonus achievement!) + +## Learning Resources + +- [GitHub Copilot Best Practices](https://docs.github.com/en/copilot/using-github-copilot/best-practices-for-using-github-copilot) +- [Prompt Engineering Guide](https://www.promptingguide.ai/) +- [Test-Driven Development Fundamentals](https://martinfowler.com/bliki/TestDrivenDevelopment.html) + +## Tips + +- Start with the spec, not the code—what are the acceptance criteria? +- Write failing tests first to establish your deterministic feedback loop +- Choose your model based on the complexity of each subtask +- Track credits as you go, not just at the end +- If you get stuck in a high-cost loop, reset: use `/clear` and try a different approach +- Remember that the fastest path isn't always the cheapest—an extra minute planning can save 20 credits executing \ No newline at end of file From e7a1ab44fa0d05526e408745282413674e6ce2f5 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:37:30 -0700 Subject: [PATCH 08/48] Refine README for clarity on prerequisites and challenges Updated README to clarify prerequisites and challenges. --- xxx-GitHubCopilotCostOptimization/README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/README.md b/xxx-GitHubCopilotCostOptimization/README.md index 0257b86220..3fa6491c71 100644 --- a/xxx-GitHubCopilotCostOptimization/README.md +++ b/xxx-GitHubCopilotCostOptimization/README.md @@ -4,7 +4,7 @@ GitHub Copilot transforms developer productivity, but with usage-based billing (UBB), every token counts. This What The Hack teaches engineering teams how to maximize code quality while minimizing AI credit spend through smart engineering practices. -You'll learn to control the three cost levers: what enters the context (instructions, attachments, MCP tools), what the model produces (model selection, output constraints), and how efficiently you use the session (cache management, context window hygiene, deterministic feedback loops). By the end, you'll understand that most Copilot cost optimization isn't about restricting usage—it's about engineering better inputs and workflows that help the agent succeed faster. +You'll learn to control the three cost levers: what enters the context (instructions, attachments, MCP tools), what the model produces (model selection, output constraints), and how efficiently you use the session (cache management, context window hygiene, deterministic feedback loops). By the end, you'll understand that most Copilot cost optimization isn't about restricting usage, it's about engineering better inputs and workflows that help the agent succeed faster. ## Learning Objectives @@ -19,8 +19,8 @@ In this hack, you will learn practical techniques to optimize GitHub Copilot usa ## Challenges -- Challenge 00: **[Prerequisites & Baseline](Student/Challenge-00.md)** - - Set up the hack environment, confirm UBB tracking is working, and establish your baseline credit spend +- Challenge 00: **[Prerequisites](Student/Challenge-00.md)** + - Set up the hack environment - Challenge 01: **[Context Engineering](Student/Challenge-01.md)** - Audit and restructure global instructions into scoped files, and replace broad references with pinned attachments - Challenge 02: **[Model Selection & Output Constraints](Student/Challenge-02.md)** @@ -36,11 +36,9 @@ In this hack, you will learn practical techniques to optimize GitHub Copilot usa ## Prerequisites -- GitHub Copilot subscription with usage-based billing (UBB) enabled -- Visual Studio Code with GitHub Copilot extension installed -- Access to GitHub Copilot usage dashboard -- Basic understanding of software development concepts (testing, linting, version control) -- Familiarity with command-line tools and development environments +- GitHub Copilot subscription +- GitHub Copilot Fundamentals +- Visual Studio Code OR IDE of choice with GitHub Copilot extension installed ## Repository Contents From af190a2ee1aa58725559f860ba90dc64895821eb Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:44:21 -0700 Subject: [PATCH 09/48] Update to follow guidelines --- .../Student/Challenge-01.md | 47 +++++--------- .../Student/Challenge-04.md | 55 +++++----------- .../Student/Challenge-05.md | 64 ++++--------------- 3 files changed, 43 insertions(+), 123 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md index 8cd541f642..bf6d352b1b 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md @@ -10,52 +10,37 @@ In this challenge, you'll learn to engineer your context precisely. You'll audit ## Description -The starter codebase includes an intentionally bloated `.github/copilot-instructions.md` file (~1500 tokens) that loads on every GitHub Copilot interaction. Your task is to optimize the context architecture through two experiments. +The starter codebase includes an intentionally bloated `.github/copilot-instructions.md` file that loads on every GitHub Copilot interaction. Your challenge is to reduce the base cost of every interaction through context optimization. -### Part A: Instruction Scoping +### Instruction Scoping -Audit the global instructions file and identify rules that: +Audit the global instructions file and restructure it for efficiency: -- Only apply to specific file types or directories -- Are redundant with existing linters, type checkers, or code standards -- Could be converted to GitHub Copilot Skills that activate conditionally -- Genuinely need to be global (keep these minimal) +- Identify which rules apply universally vs. only to specific languages or directories +- Minimize the global file by moving scoped rules to appropriate locations +- Consider converting task-specific patterns to GitHub Copilot Skills that activate conditionally +- Discover how language-specific and path-specific instruction files work -Restructure your instructions: +### Attachment Precision -- Keep only universal rules (target: under 500 tokens) in the global `.github/copilot-instructions.md` -- Move language-specific rules to `.github/copilot-instructions-LANGUAGE.md` files (e.g., `copilot-instructions-python.md`) -- Move directory-specific rules to path-scoped instruction files (e.g., `src/api/.github/copilot-instructions.md`) -- Convert task-specific patterns to GitHub Copilot Skills where appropriate +Experiment with workspace references to understand their token cost: -### Part B: Attachment Precision +- Compare using `#Codebase` vs. pinning specific files for the same coding task +- Measure the token difference between broad and precise attachment strategies +- Verify that output quality remains equivalent with more precise attachments -The starter codebase may include prompts that reference `#Codebase` or other broad workspace selectors. Identify one coding task where you can: - -- Replace a broad `#Codebase` reference with specific pinned files/line ranges -- Demonstrate the token difference between the two approaches -- Verify the output quality remains equivalent - -### Measurement - -Complete the same coding task from Challenge 00 (baseline) three times: - -- Attempt 1: Using the original bloated global instructions (~1500 tokens) -- Attempt 2: Using your optimized instruction architecture -- Attempt 3: Using optimized instructions + pinned attachments instead of broad references - -Record credits consumed for each attempt and calculate the reduction percentage. +Use the baseline coding task from Challenge 00 to measure the impact of your optimizations. Compare credit consumption before and after restructuring to demonstrate measurable savings. ## Success Criteria To complete this challenge successfully, you should be able to: -- Demonstrate that your restructured global `.github/copilot-instructions.md` is under 500 tokens +- Demonstrate that your restructured global `.github/copilot-instructions.md` is significantly smaller than the original - Show path-specific or language-specific instruction files you created with rules moved from the global file - Verify that at least one task-specific pattern has been converted to a GitHub Copilot Skill - Show token count comparison between using `#Codebase` vs. pinned file attachments for a specific task -- Demonstrate credit reduction across three attempts of the baseline coding task -- Verify that code quality remained equivalent across all three attempts +- Demonstrate measurable credit reduction on the baseline coding task +- Verify that code quality remained equivalent after optimization ## Learning Resources diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md index 3206c043aa..3acd162a92 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md @@ -4,67 +4,42 @@ ## Introduction -Context windows grow with every interaction. As your session accumulates messages, attachments, and generated code, the context window fills. Beyond 60-70% utilization, quality degrades—responses become less accurate, the model "forgets" earlier decisions, and credits burn faster as you pay to transmit bloated context. +Context windows grow with every interaction. As your session accumulates messages, attachments, and generated code, the context window fills. When utilization gets too high, quality degrades—responses become less accurate, the model "forgets" earlier decisions, and credits burn faster as you pay to transmit bloated context. In this challenge, you'll learn when and how to use `/compact` (the steering wheel) vs. `/clear` (the reset button). The biggest avoidable cost isn't running `/compact` too often—it's running it too late, after context rot has already degraded quality and forced expensive recovery loops. ## Description -Complete a multi-turn coding task designed to intentionally grow your context window past 60-70% utilization. You'll compare two approaches: proactive compaction vs. reactive recovery. +Complete a multi-turn coding task designed to intentionally grow your context window. You'll compare two approaches: proactive compaction vs. reactive recovery. -### Part A: Context Rot Observation +### Context Rot Observation -Start a coding task that involves multiple related features or refactors. Intentionally: +Start a coding task that involves multiple related features or refactors. Intentionally let the context window grow by adding numerous file attachments, requesting verbose explanations, and allowing the conversation to accumulate without intervention. -- Add numerous file attachments -- Request verbose explanations -- Include implementation details in chat responses -- Allow the context window to grow without intervention +Monitor context window utilization (visible in VS Code status bar or Output panel) and observe what happens as it fills. Look for quality degradation signals like inconsistencies, forgotten requirements, or repeated questions. Record credits consumed and note any incorrect outputs or rework needed. -Monitor context window utilization (visible in VS Code status bar or Output panel). Once you reach 70-80% capacity: +### Proactive Compaction -- Observe quality degradation (inconsistencies, forgotten requirements, repeated questions) -- Record credits consumed to reach this point -- Note any incorrect outputs or rework needed +Restart the same multi-turn task using proactive `/compact` at natural breakpoints (after completing a feature, before switching topics). Keep the context window lean throughout and monitor how compaction summarizes previous work while preserving state. Compare credits consumed and output quality vs. the unmanaged approach. -### Part B: Proactive Compaction +### Emergency Reset -Restart the same multi-turn task using proactive `/compact`: +Demonstrate when `/clear` is appropriate by starting a task where you realize mid-way that your approach is fundamentally wrong. Use `/clear` to wipe context and start fresh with a corrected approach. Understand the cold cache penalty from `/clear` vs. preserved cache with `/compact`. -- Use `/compact` at natural breakpoints (after completing a feature, before switching topics) -- Target: keep context window below 60% utilization throughout -- Monitor how compaction summarizes previous work while preserving state -- Compare credits consumed vs. Part A -- Compare output quality vs. Part A +### Context Management Strategy -### Part C: Emergency Reset - -Demonstrate when `/clear` is appropriate: - -- Start a task where you realize mid-way that your approach is fundamentally wrong -- Use `/clear` to wipe context and start fresh with corrected approach -- Understand the cold cache penalty from `/clear` vs. preserved cache with `/compact` -- Measure the credit cost difference - -### Context Window Hygiene Rules - -Develop and document your team's rules for context management: - -- At what context utilization percentage do you run `/compact`? -- What are "natural breakpoints" for your workflow (feature completion, test passing, architecture decision)? -- When is `/clear` better than `/compact` (fundamental direction change, context poisoning)? -- How do you balance cache preservation vs. context hygiene? +Develop and document your team's rules for context management: when to compact, what constitutes "natural breakpoints," when to clear vs. compact, and how to balance cache preservation vs. context hygiene. ## Success Criteria To complete this challenge successfully, you should be able to: -- Demonstrate observable quality degradation when context window exceeds 70% utilization -- Show credit cost comparison between no-compaction (Part A) and proactive compaction (Part B) approaches +- Demonstrate observable quality degradation when context window grows too large +- Show credit cost comparison between unmanaged context growth and proactive compaction approaches - Verify that proactive `/compact` maintained output quality throughout the multi-turn task - Demonstrate appropriate use of `/clear` when the context becomes fundamentally misaligned - Explain the difference in cache impact between `/compact` (preserves cache) and `/clear` (cold restart) -- Document your team's context management rules with specific utilization thresholds +- Document your team's context management strategy with specific decision criteria ## Learning Resources @@ -74,7 +49,7 @@ To complete this challenge successfully, you should be able to: ## Tips -- Context rot starts around 60-70% window utilization—don't wait until 90% +- Context rot starts when the window gets too full—don't wait until the last moment - `/compact` is the steering wheel (summarize, preserve state)—use it proactively - `/clear` is the reset button (wipe everything)—use it when direction changes - Natural breakpoints: feature complete, tests passing, architecture decision made diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index 51a1b5dab0..bf128bcee3 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -12,74 +12,34 @@ In this challenge, you'll demonstrate that spec-first development isn't just goo You'll implement the same feature twice: once with no spec (trial-and-error), and once with spec-first (deterministic feedback). Compare credit spend and output correctness between the two approaches. -### Part A: Trial-and-Error Development +### Trial-and-Error Development -Implement a moderately complex feature using only a vague prompt: +Implement a moderately complex feature using only a vague prompt. Provide GitHub Copilot with a high-level goal without tests, types, interfaces, or acceptance criteria. Let the agent explore, make mistakes, and iterate naturally. -- Provide GitHub Copilot with a high-level goal (e.g., "add user authentication") -- Do NOT provide tests, types, interfaces, or acceptance criteria -- Do NOT establish linting or type-checking as part of your workflow -- Let the agent explore, make mistakes, and iterate +Observe and record: retry loops, total credits consumed, discovery time, recovery effort, and final code quality. -Observe and record: +### Spec-First Development -- How many retry loops occur (agent generates code, you test, it fails, agent fixes) -- Total credits consumed -- Time spent on discovery (agent asking clarifying questions) -- Time spent on recovery (fixing incorrect implementations) -- Final code quality +Implement the same feature using spec-first approach. Before prompting GitHub Copilot, establish your specification: type definitions or interfaces, failing test cases (TDD style), clear acceptance criteria, and enabled linters/type checkers. -### Part B: Spec-First Development +Then prompt GitHub Copilot with references to your spec and tests, instructing it to implement the feature to make tests pass. -Implement the same feature using spec-first approach: +Observe and record: iterations needed, total credits consumed, whether the agent closed the loop quickly, and final code quality. -**Before prompting GitHub Copilot, create:** -- Type definitions or interfaces that define the shape of your solution -- Test cases that specify expected behavior (these can fail initially—TDD style) -- Clear acceptance criteria in your prompt or attached specification file -- Enable linters and type checkers in your workflow +### Understanding Feedback Loops -**Then prompt GitHub Copilot with:** -- A link to your type definitions/interfaces -- A link to your failing tests -- Clear acceptance criteria -- Instruction: "Implement this feature to make these tests pass" - -Observe and record: - -- How many iterations needed (should be significantly fewer) -- Total credits consumed -- Whether the agent closed the loop in one pass vs. multiple retries -- Final code quality - -### The Feedback Loop Hierarchy - -Rank feedback mechanisms by cost and latency: - -- **Fastest/Cheapest:** Type errors (instant feedback, zero credit cost) -- **Fast/Cheap:** Linter violations (seconds, zero credit cost) -- **Medium:** Unit tests (seconds, zero credit cost) -- **Slow/Expensive:** Agent trial-and-error (minutes, high credit cost) - -### Key Concepts - -Document your understanding of how deterministic controls reduce token spend: - -- When tests catch errors deterministically, the agent doesn't spend turns discovering the error through iteration -- Type checkers provide instant feedback loops (zero credits) vs. agent debugging (high credits) -- The research → plan → implement loop: sessions that skip research/planning burn tokens regenerating context after the first wrong turn -- CI signals (test pass/fail, lint pass/fail, security scan results) close loops in one tool call instead of three model turns +Rank feedback mechanisms by cost and latency to understand which are most efficient. Document how deterministic controls (tests catching errors, type checkers providing instant feedback, CI signals) reduce token spend compared to agent trial-and-error loops. ## Success Criteria To complete this challenge successfully, you should be able to: -- Demonstrate completion of a feature using trial-and-error (Part A) and spec-first (Part B) approaches +- Demonstrate completion of a feature using both trial-and-error and spec-first approaches - Show measured credit costs for both approaches with the same feature complexity - Verify that spec-first approach required fewer retry loops than trial-and-error -- Demonstrate at least 30% credit reduction using spec-first vs. trial-and-error +- Demonstrate significant credit reduction using spec-first vs. trial-and-error - Show that spec-first output met acceptance criteria with fewer iterations -- Explain how at least three deterministic controls (tests, types, linters) act as token controls +- Explain how deterministic controls (tests, types, linters) act as token controls - Document your feedback loop hierarchy ranking mechanisms by speed and cost ## Learning Resources From 33d0e227c1cd14060dd06c48744c87e7058bf885 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:54:48 -0700 Subject: [PATCH 10/48] removing less steps --- .../Student/Challenge-02.md | 56 +++++------------- .../Student/Challenge-03.md | 58 ++++--------------- .../Student/Challenge-06.md | 42 ++------------ 3 files changed, 29 insertions(+), 127 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md index 72ca4e1c35..771562cf34 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md @@ -12,51 +12,27 @@ The key insight: credit cost = (input tokens × input rate) + (output tokens × Complete the same coding task from your baseline using different GitHub Copilot models and configurations. Your goal is to understand the cost-quality tradeoff and discover when cheaper models with constraints beat expensive models without them. -### Part A: Model Comparison +### Model Comparison -Complete your baseline coding task using each available model/reasoning level combination: +Experiment with the available models in your GitHub Copilot configuration (GPT-4o, Claude Sonnet, Claude Haiku if available, etc.). Complete your baseline coding task with different models and record the total credits consumed, output quality, iteration count, and response verbosity for each. -- GPT-4o (standard agent mode) -- Claude Sonnet (standard agent mode) -- Claude Haiku (if available via custom agent) -- Any other models available in your GitHub Copilot configuration +### Output Constraints -For each model: +Explore how output constraints affect cost. Choose one model and complete the same task with different constraint approaches: no constraints, code-only output, structured formats, or word limits. Measure how these constraints affect token count and credit cost. -- Record total credits consumed -- Record output quality (does it meet acceptance criteria?) -- Record number of iterations needed to reach a working solution -- Note the model's response verbosity (tokens generated) +### Auto Mode -### Part B: Output Constraints - -Choose one model from Part A and complete the same task multiple times with different output constraints: - -- No constraints (baseline) -- "Output code only, minimal explanation" -- Structured output (e.g., JSON schema for configuration, specific code format) -- Tight word limits for explanations ("explain in <50 words") - -Measure how output constraints affect both token count and credit cost. - -### Part C: Auto Mode Exploration - -If available, use GitHub Copilot's Auto mode (task-aware routing with cache-aware model selection) to complete the same task: - -- Observe which models Auto mode selects for different subtasks -- Note when Auto mode chooses to leverage cache vs. switch models -- Compare total credit cost vs. manually selecting a single model -- Understand the 10% discount Auto mode provides for cache-friendly routing +If GitHub Copilot's Auto mode is available, try it on the same task. Observe which models it selects for different subtasks, when it leverages cache, and how total cost compares to manual model selection. Understand the tradeoffs of automatic routing vs. manual control. ## Success Criteria To complete this challenge successfully, you should be able to: -- Demonstrate completion of the baseline task using at least three different models -- Show measured credit costs for each model with identical input conditions -- Verify that output quality met acceptance criteria for each model tested -- Demonstrate credit cost reduction from applying output constraints to at least one model -- Show comparative data proving that a cheaper model with constraints can beat an expensive model without constraints on total credit cost +- Demonstrate completion of the baseline task using multiple different models +- Show measured credit costs for each model with comparable input conditions +- Verify that output quality met acceptance criteria across model tests +- Demonstrate credit cost reduction from applying output constraints +- Show comparative data proving that a cheaper model with constraints can beat an expensive model without constraints - Explain when Auto mode provides value vs. manual model selection ## Learning Resources @@ -69,16 +45,10 @@ To complete this challenge successfully, you should be able to: - Input tokens are cheaper than output tokens for most models - Verbose explanations cost credits—request code-only output when you don't need narration -- Haiku-class models can be 85-90% cheaper than Sonnet/GPT-4 class models -- Auto mode's 10% discount comes from cache-aware routing, but only when task boundaries align with cache boundaries +- Haiku-class models can be significantly cheaper than Sonnet/GPT-4 class models +- Auto mode's discount comes from cache-aware routing, but only when task boundaries align with cache boundaries - The best model isn't always the smartest one—it's the one that solves your problem at the lowest cost -***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* - -***NOTE:** As an exception, you may provide a GitHub 'raw' link to an individual file such as a PDF or Office document, so long as it does not open the contents of the file in the What The Hack repo on the GitHub website.* - -***NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.* - *Sample challenge text for the IoT Hack Of The Century:* In this challenge, you will properly configure the thingamajig for your IoT device so that it can communicate with the mother ship. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md index a4b1754c4f..769fc1adec 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md @@ -4,61 +4,25 @@ ## Introduction -Every MCP tool you enable adds 100-500 tokens per agent loop step. A session with 10 unused tools can burn thousands of extra tokens before you've written a line of code. Meanwhile, cache invalidation—triggered by switching models, toggling MCP servers, or editing system prompts mid-session—wipes your cache and forces a costly cold restart. +Every MCP tool you enable adds token overhead per agent loop step. A session with many unused tools can burn extra tokens before you've written a line of code. Meanwhile, cache invalidation—triggered by switching models, toggling MCP servers, or editing system prompts mid-session—wipes your cache and forces a costly cold restart. -In this challenge, you'll learn to configure lean sessions and maintain high cache hit rates. The engineering target is 97-98% cache efficiency. +In this challenge, you'll learn to configure lean sessions and maintain high cache hit rates. ## Description -This challenge has two parts: tool sprawl management and cache invalidation awareness. Both directly impact your per-session costs. +This challenge explores tool sprawl management and cache invalidation awareness. Both directly impact your per-session costs. -### Part A: Tool Sprawl Audit +### Tool Sprawl Audit -The starter codebase may have multiple MCP tools or GitHub Copilot extensions enabled. Your task: +The starter codebase may have multiple MCP tools or GitHub Copilot extensions enabled. Audit your current configuration to identify which tools are actually being used. Complete your baseline coding task with all tools enabled, then identify which ones were invoked (check VS Code Output panel for tool calls). Disable unused tools and repeat the task to measure credit savings. -- List all currently enabled MCP tools and extensions in your GitHub Copilot configuration -- Complete your baseline coding task with all tools enabled, recording token counts and credits -- Identify which tools were actually invoked during the task (check VS Code Output panel for tool calls) -- Disable any tools that weren't used -- Repeat the baseline task with your pruned tool configuration -- Measure credit savings from reducing tool overhead +Understand that each tool adds token overhead even when never used: tool name, description, parameter schemas, and availability announcements all cost tokens on every agent step. -Each tool adds token overhead to every agent step, even if never used. The overhead includes: +### Cache Invalidation Experiment -- Tool name and description (recurring cost) -- Tool parameter schemas (recurring cost) -- Tool availability announcements (recurring cost) +Complete the same refactor task twice under different session conditions. First, run a "clean session" where you configure once and complete the work without changes. Then run a "messy session" where you deliberately change configuration mid-task (switch models, toggle MCP servers, edit instructions). Compare total credits and cache hit rates between the two approaches. -### Part B: Cache Invalidation Experiment - -Complete the same refactor task twice under different session conditions: - -**Clean Session:** -- Start a fresh VS Code session -- Configure your chosen model and tool set -- Complete the entire refactor without changing any configuration -- Record total credits and observe cache hit rate in Output panel - -**Messy Session:** -- Start a fresh VS Code session -- Begin the refactor -- Midway through, switch to a different model -- Then toggle an MCP server off and back on -- Then edit your `.github/copilot-instructions.md` file -- Complete the refactor -- Record total credits and observe cache hit rate - -Compare the two approaches. Each configuration change invalidates the cache and triggers a cold restart penalty. - -### Cache Invalidation Triggers - -Document your understanding of what invalidates GitHub Copilot's cache: - -- Switching models mid-session -- Changing system instructions (editing copilot-instructions.md) -- Toggling MCP tools or extensions -- Switching between Agent mode and Chat mode -- Large context window changes (auto-compaction) +Document what triggers cache invalidation in GitHub Copilot: model switching, instruction edits, tool changes, mode switching, and large context changes. ## Success Criteria @@ -69,8 +33,8 @@ To complete this challenge successfully, you should be able to: - Verify which tools were actually invoked during your task (via VS Code Output panel logs) - Show comparative credit costs between clean session and messy session for the same refactor - Demonstrate measurable cache hit rate difference between the two session approaches -- Explain at least three triggers that invalidate GitHub Copilot's cache -- Achieve 95%+ cache hit rate on a multi-turn coding task +- Explain multiple triggers that invalidate GitHub Copilot's cache +- Achieve high cache hit rate on a multi-turn coding task ## Learning Resources diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-06.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-06.md index f9f1772991..67b24185e8 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-06.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-06.md @@ -10,49 +10,17 @@ Your coach has already completed this task and established a "par" score—the c ## Description -All teams will receive the same coding task with defined acceptance criteria. The task includes: - -- Functional requirements that must be implemented -- Tests that must pass -- Documentation that must exist -- Code quality standards that must be met +All teams will receive the same coding task with defined acceptance criteria from your coach. The task specification (found in the `/Challenge06/` folder of Resources.zip) includes functional requirements, tests that must pass, required documentation, and code quality standards. ### Competition Rules -Your team must: - -- Complete all functional requirements described in the task specification (found in the `/Challenge06/` folder of Resources.zip) -- Ensure all provided tests pass -- Include required documentation -- Meet code quality standards (no linting errors, proper typing where applicable) -- Document your complete approach in a "scorecard" that includes: - - Total credits consumed - - Prompt sequence used - - Model(s) selected and reasoning levels - - Optimization techniques applied from Challenges 1-5 - - Any custom techniques or strategies - -### Measurement - -Track every interaction with GitHub Copilot throughout the challenge: - -- Inline completions credit cost -- Chat interactions credit cost -- Edit commands credit cost -- Any workspace or codebase references -- Total cumulative credits for the complete task - -The team with the lowest total credit score that meets all acceptance criteria wins. In case of a tie, the team that completes first breaks the tie. +Complete all functional requirements, ensure provided tests pass, include required documentation, and meet code quality standards. Document your complete approach in a "scorecard" showing total credits consumed, prompt sequence used, models selected, and optimization techniques applied from Challenges 1-5. -### Strategic Considerations +Track every GitHub Copilot interaction throughout the challenge: inline completions, chat, edits, workspace references, and cumulative total credits. The team with the lowest total credit score that meets all acceptance criteria wins (tie-breaker: fastest completion time). -Consider applying these techniques from previous challenges: +### Strategy -- Use scoped instructions (Challenge 01) to avoid loading global context unnecessarily -- Select the most efficient model for each subtask (Challenge 02) -- Disable any MCP tools you won't need (Challenge 03) -- Use `/compact` at strategic breakpoints if needed (Challenge 04) -- Start with the spec: write tests first to create deterministic feedback loops (Challenge 05) +Consider applying techniques from previous challenges: scoped instructions, efficient model selection, pruned MCP tools, strategic `/compact` usage, and spec-first development with tests written before implementation. ## Success Criteria From 18887e4fcc41a775f4de3a2aae9683ee46f4fc75 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:56:00 -0700 Subject: [PATCH 11/48] Update Challenge-02.md --- xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md index 771562cf34..3d8d87cba2 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md @@ -16,9 +16,9 @@ Complete the same coding task from your baseline using different GitHub Copilot Experiment with the available models in your GitHub Copilot configuration (GPT-4o, Claude Sonnet, Claude Haiku if available, etc.). Complete your baseline coding task with different models and record the total credits consumed, output quality, iteration count, and response verbosity for each. -### Output Constraints +### Reasoning Levels -Explore how output constraints affect cost. Choose one model and complete the same task with different constraint approaches: no constraints, code-only output, structured formats, or word limits. Measure how these constraints affect token count and credit cost. +Explore how different reasoning levels affect credit utilization ### Auto Mode From d94472316655e2a3fd04e43cb8f2e0e1deb20937 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:57:35 -0700 Subject: [PATCH 12/48] Update Challenge-04.md --- xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md index 3acd162a92..c17ca7df64 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md @@ -26,9 +26,6 @@ Restart the same multi-turn task using proactive `/compact` at natural breakpoin Demonstrate when `/clear` is appropriate by starting a task where you realize mid-way that your approach is fundamentally wrong. Use `/clear` to wipe context and start fresh with a corrected approach. Understand the cold cache penalty from `/clear` vs. preserved cache with `/compact`. -### Context Management Strategy - -Develop and document your team's rules for context management: when to compact, what constitutes "natural breakpoints," when to clear vs. compact, and how to balance cache preservation vs. context hygiene. ## Success Criteria @@ -39,7 +36,6 @@ To complete this challenge successfully, you should be able to: - Verify that proactive `/compact` maintained output quality throughout the multi-turn task - Demonstrate appropriate use of `/clear` when the context becomes fundamentally misaligned - Explain the difference in cache impact between `/compact` (preserves cache) and `/clear` (cold restart) -- Document your team's context management strategy with specific decision criteria ## Learning Resources From 9a22d2fec633c6262f8ba3706485392694b01262 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 3 Jun 2026 13:57:59 -0700 Subject: [PATCH 13/48] Update Challenge-05.md --- xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index bf128bcee3..aa7d9ce730 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -26,10 +26,6 @@ Then prompt GitHub Copilot with references to your spec and tests, instructing i Observe and record: iterations needed, total credits consumed, whether the agent closed the loop quickly, and final code quality. -### Understanding Feedback Loops - -Rank feedback mechanisms by cost and latency to understand which are most efficient. Document how deterministic controls (tests catching errors, type checkers providing instant feedback, CI signals) reduce token spend compared to agent trial-and-error loops. - ## Success Criteria To complete this challenge successfully, you should be able to: From 368d77d432a78a95291da1fd1943b06dac3a9b21 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 10 Jun 2026 13:48:56 -0700 Subject: [PATCH 14/48] Removing duplicate template from challenges --- .../Student/Challenge-01.md | 49 ---------- .../Student/Challenge-02.md | 64 ------------- .../Student/Challenge-03.md | 70 -------------- .../Student/Challenge-04.md | 70 -------------- .../Student/Challenge-05.md | 96 ------------------- 5 files changed, 349 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md index bf6d352b1b..044dcb403d 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md @@ -55,52 +55,3 @@ To complete this challenge successfully, you should be able to: - Attachments are per-call costs—you control exactly what's included - The engineering target: keep always-on global instructions under 1000 tokens - Scoped instructions should be discoverable: if a rule only applies to `/api`, put the instruction file in `/api/.github/` - -*Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach.* - -*The success criteria should not be a list of instructions.* - -*Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."* - -*Sample success criteria for the IoT sample challenge:* - -To complete this challenge successfully, you should be able to: -- Verify that the IoT device boots properly after its thingamajig is configured. -- Verify that the thingamajig can connect to the mothership. -- Demonstrate that the thingamajic will not connect to the IoTProxyShip - -## Learning Resources - -_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ - -*Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario.* - -***Note:** Use descriptive text for each link instead of just URLs.* - -*Sample IoT resource links:* - -- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) -- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) -- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) - -## Tips - -*This section is optional and may be omitted.* - -*Add tips and hints here to give students food for thought. Sample IoT tips:* - -- IoTDevices can fail from a broken heart if they are not together with their thingamajig. Your device will display a broken heart emoji on its screen if this happens. -- An IoTDevice can have one or more thingamajigs attached which allow them to connect to multiple networks. - -## Advanced Challenges (Optional) - -*If you want, you may provide additional goals to this challenge for folks who are eager.* - -*This section is optional and may be omitted.* - -*Sample IoT advanced challenges:* - -Too comfortable? Eager to do more? Try these additional challenges! - -- Observe what happens if your IoTDevice is separated from its thingamajig. -- Configure your IoTDevice to connect to BOTH the mothership and IoTQueenBee at the same time. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md index 3d8d87cba2..a7429e23d0 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md @@ -48,67 +48,3 @@ To complete this challenge successfully, you should be able to: - Haiku-class models can be significantly cheaper than Sonnet/GPT-4 class models - Auto mode's discount comes from cache-aware routing, but only when task boundaries align with cache boundaries - The best model isn't always the smartest one—it's the one that solves your problem at the lowest cost - -*Sample challenge text for the IoT Hack Of The Century:* - -In this challenge, you will properly configure the thingamajig for your IoT device so that it can communicate with the mother ship. - -You can find a sample `thingamajig.config` file in the `/ChallengeXX` folder of the Resources.zip file provided by your coach. This is a good starting reference, but you will need to discover how to set exact settings. - -Please configure the thingamajig with the following specifications: -- Use dynamic IP addresses -- Only trust the following whitelisted servers: "mothership", "IoTQueenBee" -- Deny access to "IoTProxyShip" - -You can view an architectural diagram of an IoT thingamajig here: [Thingamajig.PDF](/Student/Resources/Architecture.PDF?raw=true). - -## Success Criteria - -*Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach.* - -*The success criteria should not be a list of instructions.* - -*Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."* - -*Sample success criteria for the IoT sample challenge:* - -To complete this challenge successfully, you should be able to: -- Verify that the IoT device boots properly after its thingamajig is configured. -- Verify that the thingamajig can connect to the mothership. -- Demonstrate that the thingamajic will not connect to the IoTProxyShip - -## Learning Resources - -_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ - -*Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario.* - -***Note:** Use descriptive text for each link instead of just URLs.* - -*Sample IoT resource links:* - -- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) -- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) -- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) - -## Tips - -*This section is optional and may be omitted.* - -*Add tips and hints here to give students food for thought. Sample IoT tips:* - -- IoTDevices can fail from a broken heart if they are not together with their thingamajig. Your device will display a broken heart emoji on its screen if this happens. -- An IoTDevice can have one or more thingamajigs attached which allow them to connect to multiple networks. - -## Advanced Challenges (Optional) - -*If you want, you may provide additional goals to this challenge for folks who are eager.* - -*This section is optional and may be omitted.* - -*Sample IoT advanced challenges:* - -Too comfortable? Eager to do more? Try these additional challenges! - -- Observe what happens if your IoTDevice is separated from its thingamajig. -- Configure your IoTDevice to connect to BOTH the mothership and IoTQueenBee at the same time. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md index 769fc1adec..36f2f40d7a 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md @@ -49,73 +49,3 @@ To complete this challenge successfully, you should be able to: - Switching models mid-session is one of the most expensive cache invalidations - Auto mode routes along cache boundaries to minimize invalidation - If you must change configuration mid-task, finish your current subtask first to preserve cache value - -***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* - -***NOTE:** As an exception, you may provide a GitHub 'raw' link to an individual file such as a PDF or Office document, so long as it does not open the contents of the file in the What The Hack repo on the GitHub website.* - -***NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.* - -*Sample challenge text for the IoT Hack Of The Century:* - -In this challenge, you will properly configure the thingamajig for your IoT device so that it can communicate with the mother ship. - -You can find a sample `thingamajig.config` file in the `/ChallengeXX` folder of the Resources.zip file provided by your coach. This is a good starting reference, but you will need to discover how to set exact settings. - -Please configure the thingamajig with the following specifications: -- Use dynamic IP addresses -- Only trust the following whitelisted servers: "mothership", "IoTQueenBee" -- Deny access to "IoTProxyShip" - -You can view an architectural diagram of an IoT thingamajig here: [Thingamajig.PDF](/Student/Resources/Architecture.PDF?raw=true). - -## Success Criteria - -*Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach.* - -*The success criteria should not be a list of instructions.* - -*Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."* - -*Sample success criteria for the IoT sample challenge:* - -To complete this challenge successfully, you should be able to: -- Verify that the IoT device boots properly after its thingamajig is configured. -- Verify that the thingamajig can connect to the mothership. -- Demonstrate that the thingamajic will not connect to the IoTProxyShip - -## Learning Resources - -_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ - -*Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario.* - -***Note:** Use descriptive text for each link instead of just URLs.* - -*Sample IoT resource links:* - -- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) -- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) -- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) - -## Tips - -*This section is optional and may be omitted.* - -*Add tips and hints here to give students food for thought. Sample IoT tips:* - -- IoTDevices can fail from a broken heart if they are not together with their thingamajig. Your device will display a broken heart emoji on its screen if this happens. -- An IoTDevice can have one or more thingamajigs attached which allow them to connect to multiple networks. - -## Advanced Challenges (Optional) - -*If you want, you may provide additional goals to this challenge for folks who are eager.* - -*This section is optional and may be omitted.* - -*Sample IoT advanced challenges:* - -Too comfortable? Eager to do more? Try these additional challenges! - -- Observe what happens if your IoTDevice is separated from its thingamajig. -- Configure your IoTDevice to connect to BOTH the mothership and IoTQueenBee at the same time. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md index c17ca7df64..51f6e6fc6c 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md @@ -51,73 +51,3 @@ To complete this challenge successfully, you should be able to: - Natural breakpoints: feature complete, tests passing, architecture decision made - The cost isn't running `/compact`—it's NOT running `/compact` until quality has already degraded - Compact before you feel the pain, not after - -***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* - -***NOTE:** As an exception, you may provide a GitHub 'raw' link to an individual file such as a PDF or Office document, so long as it does not open the contents of the file in the What The Hack repo on the GitHub website.* - -***NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.* - -*Sample challenge text for the IoT Hack Of The Century:* - -In this challenge, you will properly configure the thingamajig for your IoT device so that it can communicate with the mother ship. - -You can find a sample `thingamajig.config` file in the `/ChallengeXX` folder of the Resources.zip file provided by your coach. This is a good starting reference, but you will need to discover how to set exact settings. - -Please configure the thingamajig with the following specifications: -- Use dynamic IP addresses -- Only trust the following whitelisted servers: "mothership", "IoTQueenBee" -- Deny access to "IoTProxyShip" - -You can view an architectural diagram of an IoT thingamajig here: [Thingamajig.PDF](/Student/Resources/Architecture.PDF?raw=true). - -## Success Criteria - -*Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach.* - -*The success criteria should not be a list of instructions.* - -*Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."* - -*Sample success criteria for the IoT sample challenge:* - -To complete this challenge successfully, you should be able to: -- Verify that the IoT device boots properly after its thingamajig is configured. -- Verify that the thingamajig can connect to the mothership. -- Demonstrate that the thingamajic will not connect to the IoTProxyShip - -## Learning Resources - -_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ - -*Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario.* - -***Note:** Use descriptive text for each link instead of just URLs.* - -*Sample IoT resource links:* - -- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) -- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) -- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) - -## Tips - -*This section is optional and may be omitted.* - -*Add tips and hints here to give students food for thought. Sample IoT tips:* - -- IoTDevices can fail from a broken heart if they are not together with their thingamajig. Your device will display a broken heart emoji on its screen if this happens. -- An IoTDevice can have one or more thingamajigs attached which allow them to connect to multiple networks. - -## Advanced Challenges (Optional) - -*If you want, you may provide additional goals to this challenge for folks who are eager.* - -*This section is optional and may be omitted.* - -*Sample IoT advanced challenges:* - -Too comfortable? Eager to do more? Try these additional challenges! - -- Observe what happens if your IoTDevice is separated from its thingamajig. -- Configure your IoTDevice to connect to BOTH the mothership and IoTQueenBee at the same time. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index aa7d9ce730..069b5f2958 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -61,99 +61,3 @@ Too comfortable? Try these: - Implement pre-commit hooks that run tests/linters and provide feedback before GitHub Copilot generates fixes - Create a CI pipeline that provides GitHub Copilot with test results as context for fixing failures - Measure the credit cost difference between "fix this bug" (vague) vs. "fix this bug: test X fails with error Y" (specific) - -***This is a template for a single challenge. The italicized text provides hints & examples of what should or should NOT go in each section. You should remove all italicized & sample text and replace with your content.*** - -## Pre-requisites (Optional) - -*Your hack's "Challenge 0" should cover pre-requisites for the entire hack, and thus this section is optional and may be omitted. If you wish to spell out specific previous challenges that must be completed before starting this challenge, you may do so here.* - -## Introduction - -*This section should provide an overview of the technologies or tasks that will be needed to complete the this challenge. This includes the technical context for the challenge, as well as any new "lessons" the attendees should learn before completing the challenge.* - -*Optionally, the coach or event host is encouraged to present a mini-lesson (with a PPT or video) to set up the context & introduction to each challenge. A summary of the content of that mini-lesson is a good candidate for this Introduction section* - -*For example:* - -When setting up an IoT device, it is important to understand how 'thingamajigs' work. Thingamajigs are a key part of every IoT device and ensure they are able to communicate properly with edge servers. Thingamajigs require IP addresses to be assigned to them by a server and thus must have unique MAC addresses. In this challenge, you will get hands on with a thingamajig and learn how one is configured. - -## Description - -*This section should clearly state the goals of the challenge and any high-level instructions you want the students to follow. You may provide a list of specifications required to meet the goals. If this is more than 2-3 paragraphs, it is likely you are not doing it right.* - -***NOTE:** Do NOT use ordered lists as that is an indicator of 'step-by-step' instructions. Instead, use bullet lists to list out goals and/or specifications.* - -***NOTE:** You may use Markdown sub-headers to organize key sections of your challenge description.* - -*Optionally, you may provide resource files such as a sample application, code snippets, or templates as learning aids for the students. These files are stored in the hack's `Student/Resources` folder. It is the coach's responsibility to package these resources into a Resources.zip file and provide it to the students at the start of the hack.* - -***NOTE:** Do NOT provide direct links to files or folders in the What The Hack repository from the student guide. Instead, you should refer to the Resource.zip file provided by the coach.* - -***NOTE:** As an exception, you may provide a GitHub 'raw' link to an individual file such as a PDF or Office document, so long as it does not open the contents of the file in the What The Hack repo on the GitHub website.* - -***NOTE:** Any direct links to the What The Hack repo will be flagged for review during the review process by the WTH V-Team, including exception cases.* - -*Sample challenge text for the IoT Hack Of The Century:* - -In this challenge, you will properly configure the thingamajig for your IoT device so that it can communicate with the mother ship. - -You can find a sample `thingamajig.config` file in the `/ChallengeXX` folder of the Resources.zip file provided by your coach. This is a good starting reference, but you will need to discover how to set exact settings. - -Please configure the thingamajig with the following specifications: -- Use dynamic IP addresses -- Only trust the following whitelisted servers: "mothership", "IoTQueenBee" -- Deny access to "IoTProxyShip" - -You can view an architectural diagram of an IoT thingamajig here: [Thingamajig.PDF](/Student/Resources/Architecture.PDF?raw=true). - -## Success Criteria - -*Success criteria goes here. The success criteria should be a list of checks so a student knows they have completed the challenge successfully. These should be things that can be demonstrated to a coach.* - -*The success criteria should not be a list of instructions.* - -*Success criteria should always start with language like: "Validate XXX..." or "Verify YYY..." or "Show ZZZ..." or "Demonstrate you understand VVV..."* - -*Sample success criteria for the IoT sample challenge:* - -To complete this challenge successfully, you should be able to: -- Verify that the IoT device boots properly after its thingamajig is configured. -- Verify that the thingamajig can connect to the mothership. -- Demonstrate that the thingamajic will not connect to the IoTProxyShip - -## Learning Resources - -_List of relevant links and online articles that should give the attendees the knowledge needed to complete the challenge._ - -*Think of this list as giving the students a head start on some easy Internet searches. However, try not to include documentation links that are the literal step-by-step answer of the challenge's scenario.* - -***Note:** Use descriptive text for each link instead of just URLs.* - -*Sample IoT resource links:* - -- [What is a Thingamajig?](https://www.bing.com/search?q=what+is+a+thingamajig) -- [10 Tips for Never Forgetting Your Thingamajic](https://www.youtube.com/watch?v=dQw4w9WgXcQ) -- [IoT & Thingamajigs: Together Forever](https://www.youtube.com/watch?v=yPYZpwSpKmA) - -## Tips - -*This section is optional and may be omitted.* - -*Add tips and hints here to give students food for thought. Sample IoT tips:* - -- IoTDevices can fail from a broken heart if they are not together with their thingamajig. Your device will display a broken heart emoji on its screen if this happens. -- An IoTDevice can have one or more thingamajigs attached which allow them to connect to multiple networks. - -## Advanced Challenges (Optional) - -*If you want, you may provide additional goals to this challenge for folks who are eager.* - -*This section is optional and may be omitted.* - -*Sample IoT advanced challenges:* - -Too comfortable? Eager to do more? Try these additional challenges! - -- Observe what happens if your IoTDevice is separated from its thingamajig. -- Configure your IoTDevice to connect to BOTH the mothership and IoTQueenBee at the same time. From 3a5188e9c4fc4c521a08283942f1fbf0c639ebeb Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:28:19 -0700 Subject: [PATCH 15/48] Updating challenge 3 --- .../Coach/Solution-03.md | 205 ++++++++++++++++-- .../Student/Challenge-03.md | 61 ++++-- 2 files changed, 220 insertions(+), 46 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md index 9d8bd85284..98625d3dce 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md @@ -4,38 +4,199 @@ ## Notes & Guidance -This challenge teaches that session configuration affects both recurring costs (MCP tools) and one-time costs (cache invalidation penalties). +This challenge teaches students that MCP tools add token overhead on every request, and that configuration changes can invalidate cached context. The TypeScript repository scan scenario provides a simple, measurable task to observe these effects. ### Key Concepts to Explain -**Tool Overhead:** -- Each MCP tool adds 100-500 tokens per agent step -- Tools are advertised to the model even if never invoked -- 10 unused tools × 200 tokens × 20 agent steps = 40,000 extra tokens +**MCP Tool Overhead:** +- Each MCP tool's definition (name, description, parameter schema) is included in the system prompt +- This overhead applies to every LLM request, even if the tool is never invoked +- The GitHub MCP server typically enables 6-8 tools by default +- For the repository scan task, students likely only need `search_code` and `get_file_contents` +- Unused tools like `create_issue`, `search_users`, `list_pull_requests` add unnecessary overhead -**Cache Invalidation Triggers:** -- Switching models mid-session (biggest penalty) -- Toggling MCP tools on/off -- Editing `.github/copilot-instructions.md` -- Large context changes (auto-compaction) +**Cache Invalidation:** +- GitHub Copilot CLI uses Anthropic Claude models with prompt caching +- Cache invalidation occurs when the system prompt changes (e.g., tool definitions, instructions) +- Common triggers: toggling MCP tools, editing `.github/copilot-instructions.md`, switching models +- Clean sessions maintain stable configuration = higher cache reuse = lower costs +- Messy sessions with mid-task changes = cache invalidation = reprocessing overhead -**Engineering Target:** -97-98% cache hit rate is achievable with clean session hygiene. +**Important Note on Documentation:** +GitHub's official documentation doesn't explicitly list cache invalidation triggers. Students discover these through experimentation by observing credit spikes after configuration changes. The underlying Anthropic prompt caching technology invalidates cache when the prompt prefix changes. + +### The Scenario + +Students use GitHub Copilot CLI to scan `microsoft/TypeScript` repository: +- Find all `package.json` files +- Find all `tsconfig.json` files +- Read main package.json for dependencies +- Generate a formatted report + +This is a multi-turn task (5-10 agent steps) that provides multiple measurement opportunities. ### Expected Time -45 minutes: -- 15 minutes: Audit and prune MCP tools -- 20 minutes: Compare clean vs. messy session -- 10 minutes: Document findings +60 minutes: +- 15 minutes: Complete initial scan with all tools, record baseline +- 10 minutes: Identify unused tools via VS Code Output panel +- 15 minutes: Disable unused tools, repeat scan, measure savings +- 15 minutes: Clean vs. messy session comparison +- 5 minutes: Document findings -### Success Criteria Validation +### Expected Measurements + +**Tool Overhead Savings:** +- Baseline: 6-8 GitHub MCP tools enabled +- Optimized: 2 tools enabled (search_code, get_file_contents) +- Removed: 4-6 unused tools +- Each unused tool: ~100-300 tokens per agent step +- Scan task: ~5-10 agent steps +- **Expected savings: 2,000-15,000 tokens (20-150 credits)** + +Actual savings vary based on: +- Model selected (Sonnet vs Haiku have different base costs) +- Number of tools initially enabled +- Complexity of tool schemas +- Number of agent steps taken + +**Cache Invalidation Impact:** +- Clean session: Configure once, complete scan = stable cache +- Messy session: Toggle tool mid-scan + edit instructions = cache invalidations +- **Expected difference: 10-30% higher cost for messy session** + +The difference may be subtle since the scan task is relatively short. Longer tasks show more dramatic cache invalidation penalties. + +### Common Blockers + +**Students Can't Find MCP Tool Configuration:** +- MCP servers are configured in Copilot CLI settings (platform-specific) +- On macOS/Linux: `~/.copilot/mcp.json` or via CLI settings +- On Windows: `%USERPROFILE%\.copilot\mcp.json` +- Students can also use `copilot mcp` command to manage servers -Students should show measurable tool overhead savings and demonstrate understanding of cache invalidation impact through comparative measurements. +**Students Don't See Tool Invocations:** +- VS Code Output panel: View → Output → select "GitHub Copilot" from dropdown +- Tool calls appear as JSON-RPC messages showing tool name and parameters +- If no tools appear, they may not have GitHub MCP server configured +- Provide example output so they know what to look for + +**Students Can't Measure Credits Accurately:** +- Use `/usage` command after each task to see credit breakdown +- GitHub Copilot usage dashboard shows cumulative spend (may be delayed) +- Encourage students to record: task name, timestamp, credits used +- Focus on relative differences (before/after) rather than absolute numbers + +**Cache Invalidation Effects Are Subtle:** +- Short tasks may not show dramatic differences +- Encourage students to make obvious changes: toggle multiple tools, edit instructions significantly +- Credit spikes may be small (10-30%) but still measurable +- The learning goal is awareness of the pattern, not hitting specific numbers ### Hints to Share -- Check VS Code Output panel for tool invocations—if a tool never appears, you don't need it enabled -- Cache hit rate visible in Output panel—look for "cache hit" vs "cache miss" counts -- Switching models mid-session is one of the most expensive cache invalidations -- If you must change configuration, finish your current subtask first to preserve cache value +**If students struggle to identify unused tools:** +- "Look for tools that never appear in the Output panel during your scan" +- "Ask yourself: did I create any issues? Did I search for users? If no, you don't need those tools" +- "For a read-only repository scan, you only need search and read tools" + +**If students can't see cache invalidation effects:** +- "Try making more dramatic changes mid-session—edit instructions significantly, toggle 2-3 tools" +- "The effect is more visible on longer tasks; your short scan may show smaller differences" +- "Focus on observing the pattern, not hitting a specific percentage" + +**If students question why this matters:** +- "In production, developers run hundreds of Copilot interactions per day" +- "Small per-request overhead × hundreds of requests = significant monthly cost" +- "Clean session hygiene is like good Git hygiene—prevents accumulated waste" + +### Technical Deep Dive (If Asked) + +**How MCP Tools Add Overhead:** + +From the Model Context Protocol specification, each tool includes: +```json +{ + "name": "get_weather", + "description": "Get current weather information for a location", + "inputSchema": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "City name or zip code" + } + }, + "required": ["location"] + } +} +``` + +This full schema is sent to the LLM on every request so the model knows: +- What tools are available +- What each tool does +- How to call them correctly + +A simple tool uses ~100-150 tokens; complex tools with many parameters use 300-500+ tokens. + +**Why Cache Invalidation Happens:** + +GitHub Copilot CLI uses Anthropic Claude models. Anthropic's prompt caching works by caching the "prompt prefix" (system instructions + tool definitions + conversation history up to a cache marker). + +If anything in that prefix changes—even one token—the cache is invalidated and must be rebuilt. This means: +- Toggling a tool → system prompt changes → cache invalidated +- Editing instructions → system prompt changes → cache invalidated +- Switching models → different model has its own cache space + +Reference: [Anthropic Prompt Caching](https://claude.com/blog/prompt-caching) + +### Success Criteria Validation + +Students successfully complete when they can show: + +1. ✅ **Tool audit documentation:** + - Screenshot or text output showing enabled tools before optimization + - Evidence of which tools were actually invoked (VS Code Output panel) + - Screenshot showing reduced tool list after optimization + +2. ✅ **Measurable savings:** + - Credit spend for baseline scan (all tools enabled) + - Credit spend for optimized scan (unused tools disabled) + - Calculated savings (even if small) + +3. ✅ **Cache invalidation observation:** + - Credit spend for clean session + - Credit spend for messy session + - Description of which changes they made mid-session + - Observation that messy session cost more + +4. ✅ **Learning articulation:** + - Can explain why unused tools cost tokens + - Can name at least 2-3 configuration changes that invalidate cache + - Understands that stable configuration = better cache reuse + +### Extension Challenges + +For teams that finish early: + +**Advanced Tool Audit:** +- Configure 3-4 different MCP servers (GitHub, filesystem, HTTP, database) +- Complete a task using only one server +- Measure overhead from all the extra unused servers + +**Model Comparison:** +- Complete the scan with Sonnet (all tools) vs Haiku (minimal tools) +- Observe that cheaper model + clean config can beat expensive model + bloated config + +**Long Session Test:** +- Use Copilot CLI for 30+ minutes of varied tasks +- Observe compaction behavior when context window fills (~80% capacity) +- Measure whether frequent configuration changes trigger more compaction + +### Additional Resources for Students + +Share after they complete the challenge: + +- [Managing Context in GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/context-management) - Official docs on context window and compaction +- [MCP Tools Specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools.md) - Details on what's included in tool schemas +- Research report saved during hack preparation with detailed citations and technical validation diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md index 36f2f40d7a..e87130e045 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md @@ -4,48 +4,61 @@ ## Introduction -Every MCP tool you enable adds token overhead per agent loop step. A session with many unused tools can burn extra tokens before you've written a line of code. Meanwhile, cache invalidation—triggered by switching models, toggling MCP servers, or editing system prompts mid-session—wipes your cache and forces a costly cold restart. +Every MCP tool you enable adds token overhead to every agent step. Each tool's name, description, and parameter schema are advertised to the model on every request—even if the tool is never invoked. A session with many unused tools burns credits before you've written a line of code. -In this challenge, you'll learn to configure lean sessions and maintain high cache hit rates. +Meanwhile, changing configuration mid-session can trigger cache invalidation, forcing expensive cold restarts where previously cached context must be reprocessed. + +In this challenge, you'll measure the real cost of tool sprawl and observe how session hygiene affects your credit spend. ## Description -This challenge explores tool sprawl management and cache invalidation awareness. Both directly impact your per-session costs. +This challenge has two parts: measuring MCP tool overhead and observing cache invalidation behavior. + +### Part 1: Measure MCP Tool Overhead + +Use GitHub Copilot to scan/find something in the `microsoft/TypeScript` repository and report back. + +If you don't have MCP servers enabled already, try the GitHub MCP server with all its tools. Complete the task with all tools enabled and record your credit spend. + +Next, identify which MCP tools were actually used. -### Tool Sprawl Audit +Disable the unused tools, repeat the scan, and measure the credit difference. Each unused tool adds token overhead on every agent step because its schema is included in the system prompt. -The starter codebase may have multiple MCP tools or GitHub Copilot extensions enabled. Audit your current configuration to identify which tools are actually being used. Complete your baseline coding task with all tools enabled, then identify which ones were invoked (check VS Code Output panel for tool calls). Disable unused tools and repeat the task to measure credit savings. +### Part 2: Observe Cache Invalidation -Understand that each tool adds token overhead even when never used: tool name, description, parameter schemas, and availability announcements all cost tokens on every agent step. +Complete the repository scan twice more under different conditions: -### Cache Invalidation Experiment +**Clean Session:** Configure your tools once, then complete the entire scan without making any configuration changes. Record total credits. -Complete the same refactor task twice under different session conditions. First, run a "clean session" where you configure once and complete the work without changes. Then run a "messy session" where you deliberately change configuration mid-task (switch models, toggle MCP servers, edit instructions). Compare total credits and cache hit rates between the two approaches. +**Messy Session:** Start the scan, but mid-way through deliberately make configuration changes—disable a tool, edit your `.github/copilot-instructions.md` file, or switch to a different reasoning effort level. Finish the scan and record total credits. -Document what triggers cache invalidation in GitHub Copilot: model switching, instruction edits, tool changes, mode switching, and large context changes. +Observe which configuration changes cause measurable credit spikes. These spikes indicate cache invalidation—when GitHub Copilot must reprocess previously cached context. ## Success Criteria To complete this challenge successfully, you should be able to: -- Show a list of all MCP tools enabled before and after your audit -- Demonstrate credit savings from disabling unused tools on the baseline task -- Verify which tools were actually invoked during your task (via VS Code Output panel logs) -- Show comparative credit costs between clean session and messy session for the same refactor -- Demonstrate measurable cache hit rate difference between the two session approaches -- Explain multiple triggers that invalidate GitHub Copilot's cache -- Achieve high cache hit rate on a multi-turn coding task +- Show which MCP tools were enabled at the start using the `/context` command +- Complete the TypeScript repository scan and generate a report with file paths and dependencies +- Identify which tools were actually invoked by examining VS Code Output panel logs +- Demonstrate measurable credit savings from disabling unused tools on the same scan task +- Show comparative credit costs between clean session and messy session approaches +- Explain which configuration changes you observed causing cache invalidation +- Document your findings: tool count before/after, credits before/after, credit difference between clean/messy sessions ## Learning Resources -- [Model Context Protocol (MCP) Overview](https://modelcontextprotocol.io/) -- [GitHub Copilot Extension Management](https://docs.github.com/en/copilot) -- [Understanding LLM Caching Strategies](https://www.anthropic.com/index/prompt-caching) +- [Managing Context in GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/context-management) +- [Model Context Protocol Tools Specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools.md) +- [Anthropic Prompt Caching](https://claude.com/blog/prompt-caching) +- [GitHub Copilot Usage-Based Billing](https://docs.github.com/en/copilot/concepts/billing/usage-based-billing-for-organizations-and-enterprises) ## Tips -- Each MCP tool costs tokens even when never invoked—they're advertised to the model at every step -- Cache hit rates above 97-98% are achievable with clean session hygiene -- Switching models mid-session is one of the most expensive cache invalidations -- Auto mode routes along cache boundaries to minimize invalidation -- If you must change configuration mid-task, finish your current subtask first to preserve cache value +- Use `/context` to see which tools are enabled and how much of your token budget they consume +- The VS Code Output panel (View → Output → "GitHub Copilot") shows actual tool invocations +- Each MCP tool's schema (name, description, parameters) is sent to the model on every request +- System prompt changes (like editing instruction files or toggling tools) can invalidate cached context +- Use `/usage` to see your credit breakdown after each task +- The GitHub MCP server typically includes tools like: search_code, get_file_contents, create_issue, search_users, list_pull_requests +- For this scanning task, you likely only need search_code and get_file_contents From 6f86dda085023865e779b373ef65cc536eaf42e7 Mon Sep 17 00:00:00 2001 From: Andressa <andressasiqueira02@outlook.com> Date: Thu, 11 Jun 2026 19:09:56 -0300 Subject: [PATCH 16/48] feat(challenge-05): Replace spec-first with Spec Kit hands-on workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Updated Challenge-05 to use GitHub Spec Kit with real commands - Added proper installation steps using uv tool install - Included full workflow: constitution → spec → plan → tasks → implement - Updated Coach guide with troubleshooting for uv installation - Added reflection questions and learning resources --- .../Coach/Solution-05.md | 151 ++++++++--- .../Student/Challenge-05.md | 242 +++++++++++++++--- 2 files changed, 327 insertions(+), 66 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md index 03293f6206..bc0cabf3a3 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md @@ -1,64 +1,145 @@ -# Challenge 05 - Spec-Driven Development - Coach's Guide +# Challenge 05 - Spec-Driven Development with Spec Kit - Coach's Guide [< Previous Solution](./Solution-04.md) - **[Home](./README.md)** - [Next Solution >](./Solution-06.md) ## Notes & Guidance -This challenge proves that deterministic controls (tests, types, linters) are token controls. When GitHub Copilot has a spec to code against, it closes the loop in one call instead of three model turns of trial-and-error. +This challenge introduces students to **GitHub Spec Kit**, a tool that enables spec-driven development with GitHub Copilot. The core insight: when you give Copilot structured context (specs), it reduces token usage and improves output quality. ### Key Concepts to Explain -**The Feedback Loop Hierarchy (Cost & Latency):** +**Spec Kit Workflow:** -1. **Type errors:** Instant feedback, zero credits -2. **Linter violations:** Seconds, zero credits -3. **Unit tests:** Seconds, zero credits -4. **Agent trial-and-error:** Minutes, high credit cost - -**Spec-First Approach:** -- Write failing tests before implementation (TDD) -- Define types/interfaces that constrain the solution space -- Establish clear acceptance criteria in the prompt -- Let the agent code against the spec +1. **Constitution:** Project-wide rules and constraints (architecture, standards, patterns) +2. **Spec:** What to build (requirements, acceptance criteria, user stories) +3. **Plan:** How to build it (architecture, stack, structure) +4. **Tasks:** Actionable work items (small, ordered, executable) +5. **Implement:** Execute tasks with Copilot **Why This Reduces Cost:** -- Tests catch errors deterministically instead of agent discovering through iteration -- Type checkers provide instant feedback vs. agent debugging -- Clear acceptance criteria prevent "did I meet the requirements?" prompting -- The research → plan → implement loop prevents expensive backtracking + +- Spec becomes persistent context — no need to repeat in every prompt +- Constitution provides guardrails that apply automatically +- Structured workflow prevents expensive backtracking +- Small tasks produce more predictable outputs than large prompts +- Clarification step catches ambiguity before implementation ### Expected Time -60 minutes: -- 25 minutes: Implement feature trial-and-error style (Part A) -- 25 minutes: Implement same feature spec-first (Part B) -- 10 minutes: Compare and document findings +45-60 minutes: +- 10 minutes: Installation and setup +- 10 minutes: Constitution and spec creation +- 10 minutes: Plan and task generation +- 15 minutes: Implementation with Copilot +- 10 minutes: Reflection and discussion + +### Setup Troubleshooting + +**uv Not Installed:** + +Students need the `uv` package manager. Install with: +```bash +# macOS/Linux +curl -LsSf https://astral.sh/uv/install.sh | sh + +# Windows (PowerShell) +powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" +``` + +See: [Install uv](https://github.com/github/spec-kit/blob/main/docs/install/uv.md) + +**Specify CLI Installation:** + +```bash +uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@vX.Y.Z +``` + +Replace `vX.Y.Z` with the latest tag from [Releases](https://github.com/github/spec-kit/releases). + +**Alternative Installation (pipx):** + +If students prefer pipx: +```bash +pipx install git+https://github.com/github/spec-kit.git@vX.Y.Z +``` + +**Spec Kit Commands Not Appearing in Copilot Chat:** + +1. Verify `.github/prompts/` folder exists with Spec Kit files +2. Reload VS Code window (Ctrl+Shift+P → "Developer: Reload Window") +3. Ensure Copilot Chat extension is up to date + +**Integration Issues:** + +If `--integration copilot` fails, try initializing without integration first: +```bash +uvx --from git+https://github.com/github/spec-kit.git specify init my-project +``` +Then manually copy prompt files to `.github/prompts/`. ### Success Criteria Validation -Students should demonstrate at least 30% credit reduction using spec-first vs. trial-and-error for the same feature complexity. +Students should be able to demonstrate: + +1. **Setup Complete:** `.specify/` and `.github/prompts/` folders exist +2. **Constitution Created:** `constitution.md` with project rules +3. **Spec Generated:** `spec.md` with requirements and acceptance criteria +4. **Plan Produced:** Architecture and structure decisions documented +5. **Tasks Listed:** Ordered list of small, actionable items +6. **Implementation Started:** At least one task executed with Copilot ### Common Blockers -**Students Don't Know How to Write Specs:** +**Students Skip Steps:** + +Emphasize the workflow is sequential by design. Each step builds on the previous. Skipping to `/speckit.implement` without a spec produces the same results as ad-hoc prompting. + +**Vague Constitution:** -Guide them: -1. Start with types/interfaces (what shape is the solution?) -2. Write failing tests (what behavior must exist?) -3. Document acceptance criteria (when am I done?) +Guide them to be specific. Bad: "Good code." Good: "Node.js with TypeScript, Express framework, repository pattern, input validation with Joi." -**Students Skip Research/Plan Phases:** +**Spec Too Large:** -Explain: The agent can help write your spec! Ask "what tests should I write for feature X?" before asking "implement feature X." +If the spec covers too much, `/speckit.plan` and `/speckit.tasks` become unwieldy. Encourage smaller, focused specs for individual features. + +**Students Want to Edit Generated Files:** + +This is fine! The generated specs/plans are starting points. Encourage editing for accuracy before proceeding. ### Hints to Share -- "Write the test first" is both good TDD and good token economics -- Let the agent help write your tests if you provide requirements -- Type errors are free feedback—leverage them before prompting for fixes -- The most expensive code is code you have to regenerate after discovering the approach was wrong -- Research → plan → implement is cheaper than implement → discover wrong → regenerate → recover +- Use `/speckit.clarify` whenever you feel the spec is ambiguous — it's designed to ask the right questions +- The constitution applies to everything — write it once, benefit everywhere +- Review the plan before generating tasks — it's easier to fix architecture issues at the plan stage +- Tasks should be small enough to complete in a single Copilot interaction +- You can re-run any command to regenerate — the workflow is iterative + +### Reflection Discussion Points + +After completion, discuss with students: + +1. **What changed?** They didn't need to repeat context in every prompt +2. **What was NOT repeated?** Requirements, architecture decisions, coding standards +3. **Predictability:** Outputs should be more consistent when following the spec +4. **Token impact:** Fewer retries, less context repetition = lower token usage ### Key Insight for Students -The single most leveraged answer to "how do I make my team more efficient with GitHub Copilot" is: give them fast deterministic feedback loops. Tests, types, and linters close loops in zero credits instead of expensive model turns. +> **Spec becomes your context. Not the chat.** + +Traditional prompting requires repeating context every time. With Spec Kit, the spec IS the context that Copilot references. This is both better engineering and better token economics. + +### Demo Script (If Students Struggle) + +1. Initialize project: Show the generated folder structure +2. Run `/speckit.constitution` and show resulting file +3. Run `/speckit.specify` with a simple requirement +4. Show how `/speckit.plan` produces architecture from the spec +5. Run `/speckit.tasks` and show the task breakdown +6. Execute one task with `/speckit.implement` + +### Connection to Other Challenges + +- **Challenge 04 (Prompt Architecture):** Spec Kit is a formalized version of structured prompting +- **Challenge 06 (Token Golf):** Spec Kit naturally reduces tokens by eliminating context repetition +- **Challenge 07 (Infrastructure):** Constitution can encode infrastructure standards diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index 069b5f2958..bdb2c7b526 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -1,63 +1,243 @@ -# Challenge 05 - Spec-Driven Development +# Challenge 05 - Spec-Driven Development with Spec Kit [< Previous Challenge](./Challenge-04.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-06.md) ## Introduction -Deterministic controls—tests, linters, type checks, and security scans—are token controls. When GitHub Copilot has a spec to code against and a fast feedback loop to verify correctness, it closes the loop in one tool call instead of three model turns of trial-and-error. Every time the agent "gambles" and discovers a mistake through iteration, you pay for discovery and recovery. +In this challenge, you will use **GitHub Spec Kit** to implement a **Spec-Driven Development workflow** with GitHub Copilot. -In this challenge, you'll demonstrate that spec-first development isn't just good engineering—it's cost optimization. +Instead of writing large prompts, you will: + +- Define a **constitution (rules)** +- Create a **spec (what to build)** +- Generate a **plan (how to build)** +- Break it into **tasks** +- Execute implementation + +**Goal:** Reduce token usage and improve output quality by using structured specs instead of ad-hoc prompts. + +> **Key Concept:** Spec becomes your context. Not the chat. + +## Prerequisites + +Make sure you have: + +- VS Code installed +- GitHub Copilot + Copilot Chat extension +- Git installed +- Python 3.11+ installed +- Internet access (for installation) ## Description -You'll implement the same feature twice: once with no spec (trial-and-error), and once with spec-first (deterministic feedback). Compare credit spend and output correctness between the two approaches. +### Setup + +#### Step 1 — Install Specify CLI + +Requires **[uv](https://docs.astral.sh/uv/)** ([install uv](https://github.com/github/spec-kit/blob/main/docs/install/uv.md)). Replace `vX.Y.Z` with the latest tag from [Releases](https://github.com/github/spec-kit/releases): + +```bash +uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@vX.Y.Z +``` + +See the [Installation Guide](https://github.com/github/spec-kit/blob/main/docs/installation.md) for alternative methods, verification, upgrade, and troubleshooting. + +#### Step 2 — Initialize a Project + +```bash +specify init my-project --integration copilot +cd my-project +``` + +#### Step 3 — Open in VS Code + +```bash +code . +``` + +> **Tip:** To check for updates or upgrade the CLI later, use: +> ```bash +> specify self check # Check if newer release is available +> specify self upgrade # Upgrade to latest stable release +> ``` + +#### Step 4 — Verify Spec Kit is Ready + +In the project folder, you should see: + +- `.specify/` +- `.github/prompts/` +- Markdown files + +This confirms Spec Kit initialized the project successfully. + +#### Step 5 — Open Copilot Chat and Verify Commands + +1. Open Copilot Chat in VS Code +2. Click in the chat input box +3. Type: `/` + +You should see these commands available: + +- `/speckit.constitution` +- `/speckit.specify` +- `/speckit.plan` +- `/speckit.tasks` +- `/speckit.implement` + +If these appear, Spec Kit is working correctly. + +### Scenario + +You will build: + +> **A REST API for a task management system** + +Features: +- Authentication (JWT) +- CRUD operations for tasks +- Task filtering +- Basic validation -### Trial-and-Error Development +### Workflow Instructions -Implement a moderately complex feature using only a vague prompt. Provide GitHub Copilot with a high-level goal without tests, types, interfaces, or acceptance criteria. Let the agent explore, make mistakes, and iterate naturally. +#### Step 1 — Define Constitution -Observe and record: retry loops, total credits consumed, discovery time, recovery effort, and final code quality. +In Copilot Chat, run: -### Spec-First Development +``` +/speckit.constitution +``` -Implement the same feature using spec-first approach. Before prompting GitHub Copilot, establish your specification: type definitions or interfaces, failing test cases (TDD style), clear acceptance criteria, and enabled linters/type checkers. +Then describe your rules: -Then prompt GitHub Copilot with references to your spec and tests, instructing it to implement the feature to make tests pass. +``` +Node.js project with clean architecture, strong validation, and performance focus. +All endpoints must follow REST standards. +``` -Observe and record: iterations needed, total credits consumed, whether the agent closed the loop quickly, and final code quality. +This creates the `constitution.md` file containing your system rules. + +#### Step 2 — Create Spec + +Run: + +``` +/speckit.specify +``` + +Example input: + +``` +Build a task management API with authentication, CRUD operations, and filtering. +Focus on user experience and correctness. +``` + +This creates a `spec.md` file with: +- Requirements +- Acceptance criteria +- User stories + +#### Step 3 — (Optional) Clarify + +Run: + +``` +/speckit.clarify +``` + +Spec Kit will ask clarifying questions to improve your spec. This: +- Reduces ambiguity +- Reduces rework later + +#### Step 4 — Generate Plan + +Run: + +``` +/speckit.plan +``` + +This generates: +- Architecture decisions +- Technology stack +- Project structure + +#### Step 5 — Generate Tasks + +Run: + +``` +/speckit.tasks +``` + +This creates: +- List of small, actionable tasks +- Execution order + +#### Step 6 — Implement + +Run: + +``` +/speckit.implement +``` + +Now Copilot will: +- Execute tasks sequentially +- Generate code incrementally + +## Rules + +- Always follow the Spec Kit workflow order +- Do NOT skip steps +- Review each output before continuing +- Make minimal edits — avoid rewriting everything ## Success Criteria To complete this challenge successfully, you should be able to: -- Demonstrate completion of a feature using both trial-and-error and spec-first approaches -- Show measured credit costs for both approaches with the same feature complexity -- Verify that spec-first approach required fewer retry loops than trial-and-error -- Demonstrate significant credit reduction using spec-first vs. trial-and-error -- Show that spec-first output met acceptance criteria with fewer iterations -- Explain how deterministic controls (tests, types, linters) act as token controls -- Document your feedback loop hierarchy ranking mechanisms by speed and cost +- Successfully install and initialize Spec Kit with Copilot integration +- Create a constitution that defines project rules and standards +- Generate a spec from your requirements description +- Produce a structured plan from the spec +- Break the plan into executable tasks +- Implement features using the spec-driven workflow +- Demonstrate reduced token usage compared to ad-hoc prompting +- Show improved output consistency and predictability ## Learning Resources -- [Test-Driven Development Fundamentals](https://martinfowler.com/bliki/TestDrivenDevelopment.html) -- [Type Systems as Documentation](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html) -- [The Cost of Rework in Software Development](https://martinfowler.com/articles/is-quality-worth-cost.html) -- [GitHub Copilot and Test-Driven Development](https://docs.github.com/en/copilot) +- [GitHub Spec Kit Repository](https://github.com/github/spec-kit) +- [Spec Kit Installation Guide](https://deepwiki.com/github/spec-kit/2.1-installation) +- [Spec-Driven Development with GitHub Spec Kit](https://medium.com/@vamshi.rapolu/spec-driven-development-with-github-spec-kit-copilot-in-vs-code-new-existing-projects-2531d10bd61d) +- [Spec Kit Commands Reference](https://easyguides.net/guides/spec-kit/commands) +- [Plan and Tasks Commands Tutorial](https://codestandup.com/posts/2025/github-spec-kit-tutorial-plan-tasks-commands/) ## Tips -- "Write the test first" is both good TDD and good token economics -- Type errors are free feedback—leverage them before asking the agent -- Linters catch mistakes at zero credit cost—run them before prompting for fixes -- The agent can write your tests if you provide the spec, then implement against those tests -- Research → plan → implement is cheaper than implement → discover mistake → regenerate → recover -- The single most leveraged answer to "how do I make devs more efficient with Copilot" is: give them fast deterministic feedback loops +- Spec becomes your persistent context — no need to repeat requirements in every prompt +- The constitution acts as guardrails that apply to all generated code +- Use `/speckit.clarify` when requirements feel ambiguous +- Each step builds on the previous — the workflow is designed to be sequential +- Review generated specs and plans before proceeding to catch issues early +- Small, focused specs produce better results than large, vague ones + +## Reflection Questions + +After completing this challenge, answer: + +1. What changed compared to normal prompting? +2. What did you NOT have to repeat in your prompts? +3. Did the outputs become more predictable? +4. How would this workflow impact token usage in real scenarios? ## Advanced Challenges Too comfortable? Try these: -- Implement pre-commit hooks that run tests/linters and provide feedback before GitHub Copilot generates fixes -- Create a CI pipeline that provides GitHub Copilot with test results as context for fixing failures -- Measure the credit cost difference between "fix this bug" (vague) vs. "fix this bug: test X fails with error Y" (specific) +- Apply Spec Kit to an existing project instead of a new one +- Create multiple specs for different features and observe how they interact +- Measure credit consumption between spec-driven and traditional prompting for the same feature +- Customize the constitution for different project types (frontend, backend, full-stack) From 4f3f6996dace66c1f98031a7a739757c35b50cf6 Mon Sep 17 00:00:00 2001 From: Andressa <andressasiqueira02@outlook.com> Date: Fri, 19 Jun 2026 13:40:42 -0300 Subject: [PATCH 17/48] Restructure Challenge-05 to compare ad-hoc vs Spec Kit approaches - Add Part 1: Build app with ad-hoc prompting (no structure) - Add Part 2: Build same app with Spec Kit workflow - Add Part 3: Compare results between approaches - Remove installation instructions (moved to Challenge 0 prerequisites) - Clarify that Spec Kit is one of many spec-driven approaches - Update Coach guide to match new structure --- .../Coach/Solution-05.md | 89 +++++---- .../Student/Challenge-05.md | 182 +++++++++++------- 2 files changed, 158 insertions(+), 113 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md index bc0cabf3a3..d9e9e1d17c 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md @@ -4,10 +4,27 @@ ## Notes & Guidance -This challenge introduces students to **GitHub Spec Kit**, a tool that enables spec-driven development with GitHub Copilot. The core insight: when you give Copilot structured context (specs), it reduces token usage and improves output quality. +This challenge introduces students to **spec-driven development** by having them build the **same application twice**: first with ad-hoc prompting, then with **GitHub Spec Kit**. The hands-on comparison makes the benefits tangible. + +> **Note:** Spec Kit installation prerequisites are covered in Challenge 0. If students haven't completed setup, direct them there first. ### Key Concepts to Explain +**Why Two Applications?** + +Building the same thing twice demonstrates: +- How much context repetition happens with ad-hoc prompting +- How structured specs reduce cognitive load and token usage +- The difference in output consistency + +**Spec Kit is One Approach:** + +Emphasize that Spec Kit is **one of many** ways to do spec-driven development. The principle — structured context produces better results — applies regardless of tooling. Other approaches include: +- Custom instruction files (.github/copilot-instructions.md) +- Manual spec documents referenced in prompts +- Project constitution patterns +- Prompt template systems + **Spec Kit Workflow:** 1. **Constitution:** Project-wide rules and constraints (architecture, standards, patterns) @@ -26,42 +43,12 @@ This challenge introduces students to **GitHub Spec Kit**, a tool that enables s ### Expected Time -45-60 minutes: -- 10 minutes: Installation and setup -- 10 minutes: Constitution and spec creation -- 10 minutes: Plan and task generation -- 15 minutes: Implementation with Copilot -- 10 minutes: Reflection and discussion - -### Setup Troubleshooting +60-90 minutes: +- 20-30 minutes: Part 1 — Build with ad-hoc prompting +- 30-40 minutes: Part 2 — Build with Spec Kit workflow +- 10-20 minutes: Part 3 — Compare results and discussion -**uv Not Installed:** - -Students need the `uv` package manager. Install with: -```bash -# macOS/Linux -curl -LsSf https://astral.sh/uv/install.sh | sh - -# Windows (PowerShell) -powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex" -``` - -See: [Install uv](https://github.com/github/spec-kit/blob/main/docs/install/uv.md) - -**Specify CLI Installation:** - -```bash -uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@vX.Y.Z -``` - -Replace `vX.Y.Z` with the latest tag from [Releases](https://github.com/github/spec-kit/releases). - -**Alternative Installation (pipx):** - -If students prefer pipx: -```bash -pipx install git+https://github.com/github/spec-kit.git@vX.Y.Z -``` +### Troubleshooting **Spec Kit Commands Not Appearing in Copilot Chat:** @@ -81,6 +68,12 @@ Then manually copy prompt files to `.github/prompts/`. Students should be able to demonstrate: +**Part 1 — Ad-Hoc Approach:** +1. Created task-api-adhoc project +2. Built the API using conversational prompts +3. Documented observations (context repetition, inconsistencies) + +**Part 2 — Spec Kit Approach:** 1. **Setup Complete:** `.specify/` and `.github/prompts/` folders exist 2. **Constitution Created:** `constitution.md` with project rules 3. **Spec Generated:** `spec.md` with requirements and acceptance criteria @@ -88,6 +81,11 @@ Students should be able to demonstrate: 5. **Tasks Listed:** Ordered list of small, actionable items 6. **Implementation Started:** At least one task executed with Copilot +**Part 3 — Comparison:** +1. Completed the comparison table +2. Can articulate differences between approaches +3. Understands why structured specs reduce token usage + ### Common Blockers **Students Skip Steps:** @@ -118,10 +116,11 @@ This is fine! The generated specs/plans are starting points. Encourage editing f After completion, discuss with students: -1. **What changed?** They didn't need to repeat context in every prompt -2. **What was NOT repeated?** Requirements, architecture decisions, coding standards -3. **Predictability:** Outputs should be more consistent when following the spec -4. **Token impact:** Fewer retries, less context repetition = lower token usage +1. **Experience Difference:** How did Part 1 feel compared to Part 2? +2. **Context Repetition:** How many times did they repeat requirements in each approach? +3. **Consistency:** Was the Spec Kit output more predictable? +4. **Token Impact:** Fewer retries, less context repetition = lower token usage +5. **Other Approaches:** What other methods could achieve similar structured benefits? ### Key Insight for Students @@ -129,6 +128,16 @@ After completion, discuss with students: Traditional prompting requires repeating context every time. With Spec Kit, the spec IS the context that Copilot references. This is both better engineering and better token economics. +### Coaching Part 1 (Ad-Hoc) + +Let students experience the frustration! Don't intervene too quickly. Common observations: +- They had to repeat "use Node.js" multiple times +- Copilot "forgot" earlier requirements +- Code style was inconsistent between prompts +- They felt like they were re-explaining constantly + +This pain is what makes Part 2 powerful. + ### Demo Script (If Students Struggle) 1. Initialize project: Show the generated folder structure diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index bdb2c7b526..01a33a4af6 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -4,9 +4,11 @@ ## Introduction -In this challenge, you will use **GitHub Spec Kit** to implement a **Spec-Driven Development workflow** with GitHub Copilot. +In this challenge, you will experience the difference between **ad-hoc prompting** and **spec-driven development** by building the same application twice — first without structure, then using **GitHub Spec Kit**. -Instead of writing large prompts, you will: +Spec Kit is one of several ways to implement spec-driven development with GitHub Copilot. The core principle applies regardless of tooling: **structured context produces better results than conversational prompts**. + +With Spec Kit, you will: - Define a **constitution (rules)** - Create a **spec (what to build)** @@ -14,94 +16,101 @@ Instead of writing large prompts, you will: - Break it into **tasks** - Execute implementation -**Goal:** Reduce token usage and improve output quality by using structured specs instead of ad-hoc prompts. +**Goal:** Experience firsthand how structured specs reduce token usage and improve output quality compared to ad-hoc prompting. > **Key Concept:** Spec becomes your context. Not the chat. -## Prerequisites +## Description -Make sure you have: +In this challenge, you will build **the same application twice**: -- VS Code installed -- GitHub Copilot + Copilot Chat extension -- Git installed -- Python 3.11+ installed -- Internet access (for installation) +1. **Part 1:** Build with ad-hoc prompting (no structure) +2. **Part 2:** Build with Spec Kit workflow -## Description +Then compare the results. -### Setup +### The Application -#### Step 1 — Install Specify CLI +You will build: -Requires **[uv](https://docs.astral.sh/uv/)** ([install uv](https://github.com/github/spec-kit/blob/main/docs/install/uv.md)). Replace `vX.Y.Z` with the latest tag from [Releases](https://github.com/github/spec-kit/releases): +> **A REST API for a task management system** -```bash -uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@vX.Y.Z -``` +Features: +- Authentication (JWT) +- CRUD operations for tasks +- Task filtering +- Basic validation -See the [Installation Guide](https://github.com/github/spec-kit/blob/main/docs/installation.md) for alternative methods, verification, upgrade, and troubleshooting. +--- -#### Step 2 — Initialize a Project +## Part 1 — Build with Ad-Hoc Prompting -```bash -specify init my-project --integration copilot -cd my-project -``` +First, build the application using traditional prompting. -#### Step 3 — Open in VS Code +### Step 1 — Create a New Project Folder ```bash +mkdir task-api-adhoc +cd task-api-adhoc code . ``` -> **Tip:** To check for updates or upgrade the CLI later, use: -> ```bash -> specify self check # Check if newer release is available -> specify self upgrade # Upgrade to latest stable release -> ``` +### Step 2 — Build Using Conversational Prompts -#### Step 4 — Verify Spec Kit is Ready +Open Copilot Chat and use prompts like: -In the project folder, you should see: +``` +Create a REST API for task management with authentication, CRUD operations, +task filtering, and validation. Use Node.js with clean architecture. +``` -- `.specify/` -- `.github/prompts/` -- Markdown files +Continue prompting to: +- Add endpoints +- Implement authentication +- Add validation logic +- Create filtering -This confirms Spec Kit initialized the project successfully. +### Step 3 — Track Your Experience -#### Step 5 — Open Copilot Chat and Verify Commands +As you work, note: +- How many times you had to repeat context +- How many times Copilot "forgot" requirements +- Total number of prompts needed +- Any inconsistencies in generated code -1. Open Copilot Chat in VS Code -2. Click in the chat input box -3. Type: `/` +### Step 4 — Save Your Results -You should see these commands available: +Keep this project. You'll compare it later. -- `/speckit.constitution` -- `/speckit.specify` -- `/speckit.plan` -- `/speckit.tasks` -- `/speckit.implement` +--- -If these appear, Spec Kit is working correctly. +## Part 2 — Build with Spec Kit -### Scenario +Now build the **same application** using the Spec Kit workflow. -You will build: +### Step 1 — Initialize a New Spec Kit Project -> **A REST API for a task management system** +```bash +specify init task-api-speckit --integration copilot +cd task-api-speckit +code . +``` -Features: -- Authentication (JWT) -- CRUD operations for tasks -- Task filtering -- Basic validation +### Step 2 — Verify Spec Kit is Ready + +In the project folder, you should see: +- `.specify/` +- `.github/prompts/` +- Markdown files -### Workflow Instructions +In Copilot Chat, type `/` — you should see: +- `/speckit.constitution` +- `/speckit.specify` +- `/speckit.plan` +- `/speckit.tasks` +- `/speckit.implement` -#### Step 1 — Define Constitution +### Step 3 — Define Constitution In Copilot Chat, run: @@ -118,7 +127,7 @@ All endpoints must follow REST standards. This creates the `constitution.md` file containing your system rules. -#### Step 2 — Create Spec +### Step 4 — Create Spec Run: @@ -138,7 +147,7 @@ This creates a `spec.md` file with: - Acceptance criteria - User stories -#### Step 3 — (Optional) Clarify +### Step 5 — (Optional) Clarify Run: @@ -150,7 +159,7 @@ Spec Kit will ask clarifying questions to improve your spec. This: - Reduces ambiguity - Reduces rework later -#### Step 4 — Generate Plan +### Step 6 — Generate Plan Run: @@ -163,7 +172,7 @@ This generates: - Technology stack - Project structure -#### Step 5 — Generate Tasks +### Step 7 — Generate Tasks Run: @@ -175,7 +184,7 @@ This creates: - List of small, actionable tasks - Execution order -#### Step 6 — Implement +### Step 8 — Implement Run: @@ -187,37 +196,63 @@ Now Copilot will: - Execute tasks sequentially - Generate code incrementally +--- + +## Part 3 — Compare Results + +Now compare both implementations. + +### Questions to Answer + +| Aspect | Ad-Hoc Approach | Spec Kit Approach | +|--------|-----------------|-------------------| +| Total prompts needed | ? | ? | +| Times you repeated context | ? | ? | +| Code consistency | ? | ? | +| Time to complete | ? | ? | +| Quality of output | ? | ? | + +### What to Look For + +- **Context retention:** Did Copilot remember requirements? +- **Consistency:** Did the code follow the same patterns throughout? +- **Completeness:** Were all requirements addressed? +- **Token efficiency:** How much did you have to type? + ## Rules -- Always follow the Spec Kit workflow order -- Do NOT skip steps +- Complete Part 1 before starting Part 2 +- Do NOT skip steps in the Spec Kit workflow - Review each output before continuing - Make minimal edits — avoid rewriting everything +- Document your observations for comparison ## Success Criteria To complete this challenge successfully, you should be able to: -- Successfully install and initialize Spec Kit with Copilot integration +- Build the task management API using ad-hoc prompting +- Build the same API using Spec Kit workflow - Create a constitution that defines project rules and standards - Generate a spec from your requirements description - Produce a structured plan from the spec - Break the plan into executable tasks -- Implement features using the spec-driven workflow -- Demonstrate reduced token usage compared to ad-hoc prompting +- Compare both approaches and articulate the differences +- Demonstrate reduced token usage with spec-driven development - Show improved output consistency and predictability ## Learning Resources - [GitHub Spec Kit Repository](https://github.com/github/spec-kit) -- [Spec Kit Installation Guide](https://deepwiki.com/github/spec-kit/2.1-installation) +- [Spec Kit Installation Guide](https://github.com/github/spec-kit/blob/main/docs/installation.md) - [Spec-Driven Development with GitHub Spec Kit](https://medium.com/@vamshi.rapolu/spec-driven-development-with-github-spec-kit-copilot-in-vs-code-new-existing-projects-2531d10bd61d) - [Spec Kit Commands Reference](https://easyguides.net/guides/spec-kit/commands) - [Plan and Tasks Commands Tutorial](https://codestandup.com/posts/2025/github-spec-kit-tutorial-plan-tasks-commands/) ## Tips -- Spec becomes your persistent context — no need to repeat requirements in every prompt +- Part 1 intentionally feels inefficient — that's the point! +- Spec becomes your persistent context — no need to repeat requirements - The constitution acts as guardrails that apply to all generated code - Use `/speckit.clarify` when requirements feel ambiguous - Each step builds on the previous — the workflow is designed to be sequential @@ -228,10 +263,11 @@ To complete this challenge successfully, you should be able to: After completing this challenge, answer: -1. What changed compared to normal prompting? -2. What did you NOT have to repeat in your prompts? -3. Did the outputs become more predictable? -4. How would this workflow impact token usage in real scenarios? +1. How did Part 1 (ad-hoc) feel compared to Part 2 (Spec Kit)? +2. How many times did you repeat context in each approach? +3. Did the outputs become more predictable with Spec Kit? +4. How would spec-driven development impact token usage and costs in real projects? +5. What other tools or methods could achieve similar spec-driven benefits? ## Advanced Challenges @@ -239,5 +275,5 @@ Too comfortable? Try these: - Apply Spec Kit to an existing project instead of a new one - Create multiple specs for different features and observe how they interact -- Measure credit consumption between spec-driven and traditional prompting for the same feature +- Measure credit consumption between both approaches for the same feature - Customize the constitution for different project types (frontend, backend, full-stack) From 187f9bc1ba913791eb8a878e16992bb71925a334 Mon Sep 17 00:00:00 2001 From: Andressa <andressasiqueira02@outlook.com> Date: Fri, 19 Jun 2026 13:47:43 -0300 Subject: [PATCH 18/48] Simplify Challenge 05 to notes app with 2 requirements, remove sample prompts --- .../Coach/Solution-05.md | 25 ++++++-- .../Student/Challenge-05.md | 60 +++++++++---------- 2 files changed, 48 insertions(+), 37 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md index d9e9e1d17c..fb0a8039e4 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md @@ -4,10 +4,18 @@ ## Notes & Guidance -This challenge introduces students to **spec-driven development** by having them build the **same application twice**: first with ad-hoc prompting, then with **GitHub Spec Kit**. The hands-on comparison makes the benefits tangible. +This challenge introduces students to **spec-driven development** by having them build the **same simple application twice**: first with ad-hoc prompting, then with **GitHub Spec Kit**. The hands-on comparison makes the benefits tangible. > **Note:** Spec Kit installation prerequisites are covered in Challenge 0. If students haven't completed setup, direct them there first. +### The Application + +Students build a **simple notes app** with only 2 requirements: +1. CRUD operations for notes +2. Each note has a title (required) and content + +This is intentionally simple — the goal is to compare approaches, not build something complex. + ### Key Concepts to Explain **Why Two Applications?** @@ -17,6 +25,13 @@ Building the same thing twice demonstrates: - How structured specs reduce cognitive load and token usage - The difference in output consistency +**Part 1 is Intentionally Unguided:** + +Students don't get example prompts — they figure it out themselves. This: +- Creates authentic frustration with ad-hoc prompting +- Makes the Spec Kit workflow feel like a relief +- Produces genuine observations for comparison + **Spec Kit is One Approach:** Emphasize that Spec Kit is **one of many** ways to do spec-driven development. The principle — structured context produces better results — applies regardless of tooling. Other approaches include: @@ -43,10 +58,10 @@ Emphasize that Spec Kit is **one of many** ways to do spec-driven development. T ### Expected Time -60-90 minutes: -- 20-30 minutes: Part 1 — Build with ad-hoc prompting -- 30-40 minutes: Part 2 — Build with Spec Kit workflow -- 10-20 minutes: Part 3 — Compare results and discussion +45-75 minutes: +- 15-20 minutes: Part 1 — Build with ad-hoc prompting +- 20-30 minutes: Part 2 — Build with Spec Kit workflow +- 10-15 minutes: Part 3 — Compare results and discussion ### Troubleshooting diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index 01a33a4af6..15553106c4 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -33,50 +33,47 @@ Then compare the results. You will build: -> **A REST API for a task management system** +> **A simple notes application** -Features: -- Authentication (JWT) -- CRUD operations for tasks -- Task filtering -- Basic validation +Requirements: +1. Create, read, update, and delete notes (CRUD) +2. Each note must have a title (required) and content + +That's it — keep it simple! --- ## Part 1 — Build with Ad-Hoc Prompting -First, build the application using traditional prompting. +First, build the application using traditional conversational prompting with Copilot. ### Step 1 — Create a New Project Folder ```bash -mkdir task-api-adhoc -cd task-api-adhoc +mkdir notes-app-adhoc +cd notes-app-adhoc code . ``` -### Step 2 — Build Using Conversational Prompts +### Step 2 — Build the Application -Open Copilot Chat and use prompts like: +Your goal: Create a working notes application that meets the 2 requirements above. -``` -Create a REST API for task management with authentication, CRUD operations, -task filtering, and validation. Use Node.js with clean architecture. -``` +**Rules:** +- Use only Copilot Chat with ad-hoc prompts +- No pre-written specs or documentation +- Just start prompting and see what happens -Continue prompting to: -- Add endpoints -- Implement authentication -- Add validation logic -- Create filtering +**Try to complete the application on your own!** ### Step 3 — Track Your Experience As you work, note: -- How many times you had to repeat context -- How many times Copilot "forgot" requirements -- Total number of prompts needed -- Any inconsistencies in generated code +- How many prompts did you need? +- How many times did you repeat the same information? +- Did Copilot "forget" what you asked earlier? +- Was the generated code consistent in style? +- How did it feel? ### Step 4 — Save Your Results @@ -91,8 +88,8 @@ Now build the **same application** using the Spec Kit workflow. ### Step 1 — Initialize a New Spec Kit Project ```bash -specify init task-api-speckit --integration copilot -cd task-api-speckit +specify init notes-app-speckit --integration copilot +cd notes-app-speckit code . ``` @@ -118,11 +115,10 @@ In Copilot Chat, run: /speckit.constitution ``` -Then describe your rules: +Then describe your rules. Example: ``` -Node.js project with clean architecture, strong validation, and performance focus. -All endpoints must follow REST standards. +Simple local application. Clean code with clear separation of concerns. ``` This creates the `constitution.md` file containing your system rules. @@ -135,11 +131,11 @@ Run: /speckit.specify ``` -Example input: +Describe the same requirements as Part 1: ``` -Build a task management API with authentication, CRUD operations, and filtering. -Focus on user experience and correctness. +A notes application with CRUD operations. +Each note has a title (required) and content. ``` This creates a `spec.md` file with: From 463ee77a1ef1d4c90e9906fabd98ce28f7c4fc2b Mon Sep 17 00:00:00 2001 From: Devanshi Thakar <33441411+devanshithakar12@users.noreply.github.com> Date: Fri, 19 Jun 2026 14:01:49 -0400 Subject: [PATCH 19/48] initial starter code for challenge 2 --- .../.github/copilot-instructions.md | 16 ++++++++ .../Resources/Challenge-02-NYCApp/README.md | 39 +++++++++++++++++++ .../Challenge-02-NYCApp/src/data/events.ts | 7 ++++ .../src/data/neighborhoods.ts | 5 +++ .../src/data/restaurants.ts | 5 +++ .../Challenge-02-NYCApp/src/routes/events.ts | 14 +++++++ .../src/routes/neighborhoods.ts | 9 +++++ .../src/routes/restaurants.ts | 9 +++++ 8 files changed, 104 insertions(+) create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/neighborhoods.ts create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/restaurants.ts create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/events.ts create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/neighborhoods.ts create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/restaurants.ts diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md new file mode 100644 index 0000000000..d59eccf55c --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md @@ -0,0 +1,16 @@ + +# Copilot Instructions (INTENTIONALLY BLOATED) + +- Always validate inputs +- Always handle errors +- Always use REST APIs +- Always use React hooks +- Always optimize performance +- Always write tests +- Always ensure accessibility +- Always normalize JSON +- Restaurants must include cuisine and borough +- Neighborhoods must include transit and vibe +- Events must include price and date filtering + +# TOO BIG ON PURPOSE diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md new file mode 100644 index 0000000000..5cb8a00852 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md @@ -0,0 +1,39 @@ + +# CityScout NYC - Challenge 01 Starter (FULL VERSION) + +## ✅ WHERE YOU SHOULD MAKE CHANGES + +### MODIFY THESE: +1. `.github/copilot-instructions.md` +2. Create `.github/instructions/` +3. Update `src/routes/events.ts` + +### DO NOT MODIFY: +- `restaurants.ts` +- `neighborhoods.ts` + +--- + +## Baseline Task + +Implement `/events/free-this-week`: +- price === 0 +- within next 7 days +- sorted by date +- return { count, events } + +--- + +## Demo Goal + +Compare: + +❌ #Codebase (loads EVERYTHING) +✅ @events + specific files (loads ONLY events) + +Now repo includes: +✅ Events +✅ Restaurants +✅ Neighborhoods + +So you can visibly see context differences diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts new file mode 100644 index 0000000000..32484a7ad7 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts @@ -0,0 +1,7 @@ + +export const events = [ + { name: 'Central Park Yoga', date: '2026-06-20', price: 0 }, + { name: 'Brooklyn Flea Market Walk', date: '2026-06-22', price: 0 }, + { name: 'Rooftop Movie Night', date: '2026-06-25', price: 15 }, + { name: 'Jazz in Washington Square Park', date: '2026-07-10', price: 0 } +]; diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/neighborhoods.ts b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/neighborhoods.ts new file mode 100644 index 0000000000..a1b5a81feb --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/neighborhoods.ts @@ -0,0 +1,5 @@ + +export const neighborhoods = [ + { name: 'West Village', borough: 'Manhattan' }, + { name: 'Williamsburg', borough: 'Brooklyn' } +]; diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/restaurants.ts b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/restaurants.ts new file mode 100644 index 0000000000..65c0434049 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/restaurants.ts @@ -0,0 +1,5 @@ + +export const restaurants = [ + { name: 'West Village Pasta', borough: 'Manhattan', cuisine: 'Italian' }, + { name: 'Williamsburg Tacos', borough: 'Brooklyn', cuisine: 'Mexican' } +]; diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/events.ts b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/events.ts new file mode 100644 index 0000000000..9395b7efbd --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/events.ts @@ -0,0 +1,14 @@ + +import { Router } from 'express'; +import { events } from '../data/events.js'; + +export const eventsRouter = Router(); + +// ✅ STUDENTS MODIFY THIS + +eventsRouter.get('/free-this-week', (req, res) => { + return res.json({ + count: events.length, + events + }); +}); diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/neighborhoods.ts b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/neighborhoods.ts new file mode 100644 index 0000000000..7accf971dc --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/neighborhoods.ts @@ -0,0 +1,9 @@ + +import { Router } from 'express'; +import { neighborhoods } from '../data/neighborhoods.js'; + +export const neighborhoodsRouter = Router(); + +neighborhoodsRouter.get('/', (_req, res) => { + res.json(neighborhoods); +}); diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/restaurants.ts b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/restaurants.ts new file mode 100644 index 0000000000..ce7d338504 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/restaurants.ts @@ -0,0 +1,9 @@ + +import { Router } from 'express'; +import { restaurants } from '../data/restaurants.js'; + +export const restaurantsRouter = Router(); + +restaurantsRouter.get('/', (_req, res) => { + res.json(restaurants); +}); From 2c1949d0fa232596051f5c4e9db19a74a1f9d493 Mon Sep 17 00:00:00 2001 From: Devanshi Thakar <33441411+devanshithakar12@users.noreply.github.com> Date: Fri, 19 Jun 2026 14:16:45 -0400 Subject: [PATCH 20/48] initial solutions guide for challenge 2 --- .../.github/copilot-instructions.md | 6 ++++ .../.github/instructions/api.instructions.md | 9 +++++ .../instructions/events.instructions.md | 9 +++++ .../skills/free-events-endpoint/SKILL.md | 9 +++++ .../Challenge-02-NYCApp-Solutions/README.md | 36 +++++++++++++++++++ .../src/data/events.ts | 7 ++++ .../src/data/neighborhoods.ts | 5 +++ .../src/data/restaurants.ts | 5 +++ .../src/routes/events.ts | 25 +++++++++++++ .../src/routes/neighborhoods.ts | 9 +++++ .../src/routes/restaurants.ts | 9 +++++ 11 files changed, 129 insertions(+) create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/neighborhoods.ts create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/restaurants.ts create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/events.ts create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/neighborhoods.ts create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/restaurants.ts diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md new file mode 100644 index 0000000000..ba1c957141 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md @@ -0,0 +1,6 @@ + +# ✅ Optimized Global Instructions + +- Write clean, readable code +- Prefer clarity over complexity +- Return structured JSON responses diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md new file mode 100644 index 0000000000..c7d7ed7505 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md @@ -0,0 +1,9 @@ + +--- +applyTo: "src/routes/**/*.ts" +--- + +# API Rules +- Use REST conventions +- Return structured JSON responses +- Validate inputs diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md new file mode 100644 index 0000000000..6b03b8fd85 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md @@ -0,0 +1,9 @@ + +--- +applyTo: "src/routes/events.ts" +--- + +# Events Rules +- price === 0 +- within next 7 days +- sort by date ascending diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md new file mode 100644 index 0000000000..7fdc0c2946 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md @@ -0,0 +1,9 @@ + +--- +name: free-events-endpoint +--- + +Filter events: +1. price === 0 +2. next 7 days +3. sort ascending diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md new file mode 100644 index 0000000000..edfd842ee8 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md @@ -0,0 +1,36 @@ + +# CityScout NYC - ✅ Challenge 1 Complete Solution (v2) + +This is the fully optimized version showing: +- Reduced global instructions ✅ +- Scoped instructions ✅ +- Copilot Skill ✅ +- Complete endpoint ✅ +- Multi-domain repo (events + restaurants + neighborhoods) ✅ + +--- + +## ✅ Key Changes + +### Global → Reduced +Only universal rules kept + +### Scoped Instructions Added +- API rules +- Events rules + +### Skill Added +Reusable pattern for endpoint implementation + +### Endpoint Implemented +- price === 0 +- within 7 days +- sorted + +--- + +## ✅ What to Demonstrate + +❌ #Codebase → sees EVERYTHING (events + restaurants + neighborhoods) +✅ Pinned files → sees ONLY events + diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts new file mode 100644 index 0000000000..32484a7ad7 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts @@ -0,0 +1,7 @@ + +export const events = [ + { name: 'Central Park Yoga', date: '2026-06-20', price: 0 }, + { name: 'Brooklyn Flea Market Walk', date: '2026-06-22', price: 0 }, + { name: 'Rooftop Movie Night', date: '2026-06-25', price: 15 }, + { name: 'Jazz in Washington Square Park', date: '2026-07-10', price: 0 } +]; diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/neighborhoods.ts b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/neighborhoods.ts new file mode 100644 index 0000000000..a1b5a81feb --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/neighborhoods.ts @@ -0,0 +1,5 @@ + +export const neighborhoods = [ + { name: 'West Village', borough: 'Manhattan' }, + { name: 'Williamsburg', borough: 'Brooklyn' } +]; diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/restaurants.ts b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/restaurants.ts new file mode 100644 index 0000000000..65c0434049 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/restaurants.ts @@ -0,0 +1,5 @@ + +export const restaurants = [ + { name: 'West Village Pasta', borough: 'Manhattan', cuisine: 'Italian' }, + { name: 'Williamsburg Tacos', borough: 'Brooklyn', cuisine: 'Mexican' } +]; diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/events.ts b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/events.ts new file mode 100644 index 0000000000..0e4269b584 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/events.ts @@ -0,0 +1,25 @@ + +import { Router } from 'express'; +import { events } from '../data/events.js'; + +export const eventsRouter = Router(); + +const isWithin7Days = (dateStr) => { + const today = new Date(); + const eventDate = new Date(dateStr); + const diff = (eventDate - today) / (1000 * 60 * 60 * 24); + return diff >= 0 && diff <= 7; +}; + +// ✅ FINAL IMPLEMENTATION +eventsRouter.get('/free-this-week', (req, res) => { + const result = events + .filter(e => e.price === 0) + .filter(e => isWithin7Days(e.date)) + .sort((a, b) => new Date(a.date) - new Date(b.date)); + + res.json({ + count: result.length, + events: result + }); +}); diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/neighborhoods.ts b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/neighborhoods.ts new file mode 100644 index 0000000000..7accf971dc --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/neighborhoods.ts @@ -0,0 +1,9 @@ + +import { Router } from 'express'; +import { neighborhoods } from '../data/neighborhoods.js'; + +export const neighborhoodsRouter = Router(); + +neighborhoodsRouter.get('/', (_req, res) => { + res.json(neighborhoods); +}); diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/restaurants.ts b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/restaurants.ts new file mode 100644 index 0000000000..ce7d338504 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/restaurants.ts @@ -0,0 +1,9 @@ + +import { Router } from 'express'; +import { restaurants } from '../data/restaurants.js'; + +export const restaurantsRouter = Router(); + +restaurantsRouter.get('/', (_req, res) => { + res.json(restaurants); +}); From 99ecb9200f690818bd44a0c28c3b6c89980d7d51 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:18:38 -0700 Subject: [PATCH 21/48] Updating challenge numbes after shifting spec driven down to 1 --- .../Coach/README.md | 34 +-- .../Coach/Solution-01.md | 218 ++++++++------ .../Coach/Solution-02.md | 152 ++++++++-- .../Coach/Solution-03.md | 209 ++----------- .../Coach/Solution-04.md | 210 +++++++++++-- .../Coach/Solution-05.md | 175 ++--------- xxx-GitHubCopilotCostOptimization/README.md | 12 +- .../Student/Challenge-01.md | 278 ++++++++++++++++-- .../Student/Challenge-02.md | 55 ++-- .../Student/Challenge-03.md | 62 ++-- .../Student/Challenge-04.md | 61 ++-- .../Student/Challenge-05.md | 272 ++--------------- 12 files changed, 869 insertions(+), 869 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/README.md b/xxx-GitHubCopilotCostOptimization/Coach/README.md index d33197c7c1..0a0cbe3617 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/README.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/README.md @@ -12,16 +12,16 @@ This hack teaches teams to maximize code quality while minimizing GitHub Copilot - Challenge 00: **[Prerequisites & Baseline](./Solution-00.md)** - Set up the hack environment and establish baseline credit spend measurements -- Challenge 01: **[Context Engineering](./Solution-01.md)** +- Challenge 01: **[Spec-Driven Development](./Solution-01.md)** + - Leverage deterministic controls as token controls +- Challenge 02: **[Context Engineering](./Solution-02.md)** - Optimize instruction architecture and attachment precision -- Challenge 02: **[Model Selection & Output Constraints](./Solution-02.md)** +- Challenge 03: **[Model Selection & Output Constraints](./Solution-03.md)** - Compare models and apply output constraints to reduce costs -- Challenge 03: **[Session Configuration (Tools + Cache)](./Solution-03.md)** +- Challenge 04: **[Session Configuration (Tools + Cache)](./Solution-04.md)** - Manage MCP tool sprawl and understand cache invalidation -- Challenge 04: **[Context Window Management](./Solution-04.md)** +- Challenge 05: **[Context Window Management](./Solution-05.md)** - Use /compact proactively to maintain quality and control costs -- Challenge 05: **[Spec-Driven Development](./Solution-05.md)** - - Leverage deterministic controls as token controls - Challenge 06: **[Token Golf Competition](./Solution-06.md)** - Competitive coding challenge optimizing for lowest credit spend @@ -38,8 +38,8 @@ Before the hack, it is the Coach's responsibility to download and package up the The Student/Resources folder should contain: - **Starter codebase** with intentionally sub-optimal GitHub Copilot configuration: - - Bloated `.github/copilot-instructions.md` (~1500 tokens) for Challenge 01 - - Multiple MCP tools enabled (some unnecessary) for Challenge 03 + - Bloated `.github/copilot-instructions.md` (~1500 tokens) for Challenge 02 + - Multiple MCP tools enabled (some unnecessary) for Challenge 04 - Sample code with opportunities for spec-first vs. trial-and-error comparison - **Baseline coding task** (baseline-task.md) for Challenge 00 - **Token Golf task specification** for Challenge 06 with acceptance criteria @@ -72,20 +72,20 @@ This hack can be delivered as a half-day or full-day event: ### Half-Day Format (4 hours) - Challenge 00: Prerequisites & Baseline (30 minutes) -- Challenge 01: Context Engineering (45 minutes) -- Challenge 02: Model Selection & Output Constraints (45 minutes) -- Challenge 03: Session Configuration (30 minutes) -- Challenge 05: Spec-Driven Development (45 minutes) +- Challenge 01: Spec-Driven Development (45 minutes) +- Challenge 02: Context Engineering (45 minutes) +- Challenge 03: Model Selection & Output Constraints (45 minutes) +- Challenge 04: Session Configuration (30 minutes) - Challenge 06: Token Golf Competition (45 minutes) ### Full-Day Format (6-7 hours) - Challenge 00: Prerequisites & Baseline (45 minutes) -- Challenge 01: Context Engineering (60 minutes) -- Challenge 02: Model Selection & Output Constraints (60 minutes) +- Challenge 01: Spec-Driven Development (60 minutes) +- Challenge 02: Context Engineering (60 minutes) - Break (15 minutes) -- Challenge 03: Session Configuration (45 minutes) -- Challenge 04: Context Window Management (45 minutes) -- Challenge 05: Spec-Driven Development (60 minutes) +- Challenge 03: Model Selection & Output Constraints (60 minutes) +- Challenge 04: Session Configuration (45 minutes) +- Challenge 05: Context Window Management (45 minutes) - Break (15 minutes) - Challenge 06: Token Golf Competition (60 minutes) - Debrief & Winning Strategies (30 minutes) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md index 8006c0f7cb..6b3e6e7c65 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md @@ -1,145 +1,169 @@ -# Challenge 01 - Context Engineering - Coach's Guide +# Challenge 01 - Spec-Driven Development with Spec Kit - Coach's Guide [< Previous Solution](./Solution-00.md) - **[Home](./README.md)** - [Next Solution >](./Solution-02.md) ## Notes & Guidance -This challenge teaches students that persistent context has recurring costs. The goal is to minimize always-on overhead while maintaining quality through scoped instructions and precise attachments. +This challenge introduces students to **spec-driven development** by having them build the **same simple application twice**: first with ad-hoc prompting, then with **GitHub Spec Kit**. The hands-on comparison makes the benefits tangible. + +> **Note:** Spec Kit installation prerequisites are covered in Challenge 0. If students haven't completed setup, direct them there first. + +### The Application + +Students build a **simple notes app** with only 2 requirements: +1. CRUD operations for notes +2. Each note has a title (required) and content + +This is intentionally simple — the goal is to compare approaches, not build something complex. ### Key Concepts to Explain -**The Three Types of Context Costs:** +**Why Two Applications?** -1. **Persistent Instructions (recurring cost):** - - `.github/copilot-instructions.md` loads on EVERY interaction - - Example: 1500-token global file = 1500 tokens × every chat/edit call - - Target: keep global instructions under 500-1000 tokens +Building the same thing twice demonstrates: +- How much context repetition happens with ad-hoc prompting +- How structured specs reduce cognitive load and token usage +- The difference in output consistency -2. **GitHub Copilot Skills (conditional cost):** - - Only load when explicitly invoked - - Example: `@workspace /new` only loads creation templates when called - - Best for: task-specific patterns that don't apply to all work +**Part 1 is Intentionally Unguided:** -3. **Attachments (per-call cost):** - - You control exactly what's included each time - - Example: `#file:src/api/routes.ts` only loads when you attach it - - `#Codebase` can pull in thousands of unnecessary tokens +Students don't get example prompts — they figure it out themselves. This: +- Creates authentic frustration with ad-hoc prompting +- Makes the Spec Kit workflow feel like a relief +- Produces genuine observations for comparison -### Part A: Instruction Scoping Strategy +**Spec Kit is One Approach:** -**Audit Process:** +Emphasize that Spec Kit is **one of many** ways to do spec-driven development. The principle — structured context produces better results — applies regardless of tooling. Other approaches include: +- Custom instruction files (.github/copilot-instructions.md) +- Manual spec documents referenced in prompts +- Project constitution patterns +- Prompt template systems -Help students categorize their bloated instructions: +**Spec Kit Workflow:** -- **Keep Global (under 500 tokens):** - - Code style preferences that apply universally (e.g., "prefer functional patterns") - - Quality standards (e.g., "always handle errors explicitly") - - Organization-wide conventions +1. **Constitution:** Project-wide rules and constraints (architecture, standards, patterns) +2. **Spec:** What to build (requirements, acceptance criteria, user stories) +3. **Plan:** How to build it (architecture, stack, structure) +4. **Tasks:** Actionable work items (small, ordered, executable) +5. **Implement:** Execute tasks with Copilot -- **Move to Language-Specific:** - - `.github/copilot-instructions-python.md` for Python-only rules - - `.github/copilot-instructions-typescript.md` for TypeScript-only rules - - These only load when working in that language +**Why This Reduces Cost:** -- **Move to Path-Specific:** - - `src/api/.github/copilot-instructions.md` for API-specific patterns - - `tests/.github/copilot-instructions.md` for testing conventions - - These only load when working in that directory +- Spec becomes persistent context — no need to repeat in every prompt +- Constitution provides guardrails that apply automatically +- Structured workflow prevents expensive backtracking +- Small tasks produce more predictable outputs than large prompts +- Clarification step catches ambiguity before implementation -- **Convert to Skills:** - - Task-specific templates (e.g., "how to write a migration") - - Conditional patterns (e.g., "when adding a new model, do X") +### Expected Time -**Expected Savings:** +45-75 minutes: +- 15-20 minutes: Part 1 — Build with ad-hoc prompting +- 20-30 minutes: Part 2 — Build with Spec Kit workflow +- 10-15 minutes: Part 3 — Compare results and discussion -- Before: ~1500 tokens per interaction (global instructions) -- After: ~400 tokens global + ~200 tokens scoped (only when in scope) -- Result: 60-70% reduction in instruction overhead for most interactions +### Troubleshooting -### Part B: Attachment Precision +**Spec Kit Commands Not Appearing in Copilot Chat:** -**Common Anti-Pattern:** +1. Verify `.github/prompts/` folder exists with Spec Kit files +2. Reload VS Code window (Ctrl+Shift+P → "Developer: Reload Window") +3. Ensure Copilot Chat extension is up to date +**Integration Issues:** + +If `--integration copilot` fails, try initializing without integration first: +```bash +uvx --from git+https://github.com/github/spec-kit.git specify init my-project ``` -Prompt: "Refactor the authentication logic" -Attachments: #Codebase -``` -This pulls in everything—potentially 50,000+ tokens for a large repo. +Then manually copy prompt files to `.github/prompts/`. -**Optimized Pattern:** +### Success Criteria Validation -``` -Prompt: "Refactor the authentication logic" -Attachments: - - #file:src/auth/middleware.ts:1-50 - - #file:src/auth/types.ts - - #file:tests/auth.test.ts -``` -This pulls in exactly what's needed—perhaps 500 tokens. +Students should be able to demonstrate: -**Demonstration Exercise:** +**Part 1 — Ad-Hoc Approach:** +1. Created task-api-adhoc project +2. Built the API using conversational prompts +3. Documented observations (context repetition, inconsistencies) -Have students complete the same refactor twice: -1. With `#Codebase` (record token count from Output panel) -2. With pinned files (record token count) +**Part 2 — Spec Kit Approach:** +1. **Setup Complete:** `.specify/` and `.github/prompts/` folders exist +2. **Constitution Created:** `constitution.md` with project rules +3. **Spec Generated:** `spec.md` with requirements and acceptance criteria +4. **Plan Produced:** Architecture and structure decisions documented +5. **Tasks Listed:** Ordered list of small, actionable items +6. **Implementation Started:** At least one task executed with Copilot -Typical results: 10,000+ tokens → 800 tokens (90%+ reduction) +**Part 3 — Comparison:** +1. Completed the comparison table +2. Can articulate differences between approaches +3. Understands why structured specs reduce token usage ### Common Blockers -**Students Don't Know What to Keep Global:** +**Students Skip Steps:** -Rule of thumb: If a rule only applies to 20% of your codebase, it shouldn't be global. +Emphasize the workflow is sequential by design. Each step builds on the previous. Skipping to `/speckit.implement` without a spec produces the same results as ad-hoc prompting. -**Path-Specific Instructions Not Loading:** +**Vague Constitution:** -GitHub Copilot walks up the directory tree looking for `.github/copilot-instructions.md` files. Ensure: -- Directory structure is correct -- File is named exactly `.github/copilot-instructions.md` (not `.github/copilot-instructions-api.md` in the api folder) +Guide them to be specific. Bad: "Good code." Good: "Node.js with TypeScript, Express framework, repository pattern, input validation with Joi." -**Can't Measure Token Reduction:** +**Spec Too Large:** -- VS Code Output panel (View → Output → "GitHub Copilot Chat") shows token counts -- If not visible, update GitHub Copilot extension to latest version +If the spec covers too much, `/speckit.plan` and `/speckit.tasks` become unwieldy. Encourage smaller, focused specs for individual features. -### Expected Time +**Students Want to Edit Generated Files:** -60 minutes total: -- 20 minutes: Audit and categorize global instructions -- 20 minutes: Restructure into scoped files -- 20 minutes: Test attachment precision and measure savings +This is fine! The generated specs/plans are starting points. Encourage editing for accuracy before proceeding. -### Success Criteria Validation +### Hints to Share -Students should demonstrate: -- Global `.github/copilot-instructions.md` reduced to under 500 tokens -- At least one path-specific or language-specific instruction file created -- Token comparison showing savings from pinned attachments vs. `#Codebase` -- Same baseline task completed with reduced credit cost +- Use `/speckit.clarify` whenever you feel the spec is ambiguous — it's designed to ask the right questions +- The constitution applies to everything — write it once, benefit everywhere +- Review the plan before generating tasks — it's easier to fix architecture issues at the plan stage +- Tasks should be small enough to complete in a single Copilot interaction +- You can re-run any command to regenerate — the workflow is iterative -### Hints to Share +### Reflection Discussion Points -- Start by asking: "Does this rule apply to ALL code I write?" If no, scope it -- Use language-specific files for linting/formatting rules that vary by language -- Use path-specific files for architectural patterns (e.g., API conventions in `src/api/`) -- Pin files when you know exactly what you need; use `#Codebase` only for discovery -- The goal isn't zero instructions—it's right-sized instructions +After completion, discuss with students: -### Reference Solutions +1. **Experience Difference:** How did Part 1 feel compared to Part 2? +2. **Context Repetition:** How many times did they repeat requirements in each approach? +3. **Consistency:** Was the Spec Kit output more predictable? +4. **Token Impact:** Fewer retries, less context repetition = lower token usage +5. **Other Approaches:** What other methods could achieve similar structured benefits? -Typical restructuring: +### Key Insight for Students -**Before (1500 tokens global):** -``` -.github/copilot-instructions.md (all rules) -``` +> **Spec becomes your context. Not the chat.** -**After (400 tokens global + scoped):** -``` -.github/copilot-instructions.md (universal rules, ~400 tokens) -.github/copilot-instructions-python.md (Python-specific, ~300 tokens) -.github/copilot-instructions-typescript.md (TypeScript-specific, ~250 tokens) -src/api/.github/copilot-instructions.md (API patterns, ~200 tokens) -``` +Traditional prompting requires repeating context every time. With Spec Kit, the spec IS the context that Copilot references. This is both better engineering and better token economics. + +### Coaching Part 1 (Ad-Hoc) + +Let students experience the frustration! Don't intervene too quickly. Common observations: +- They had to repeat "use Node.js" multiple times +- Copilot "forgot" earlier requirements +- Code style was inconsistent between prompts +- They felt like they were re-explaining constantly + +This pain is what makes Part 2 powerful. + +### Demo Script (If Students Struggle) + +1. Initialize project: Show the generated folder structure +2. Run `/speckit.constitution` and show resulting file +3. Run `/speckit.specify` with a simple requirement +4. Show how `/speckit.plan` produces architecture from the spec +5. Run `/speckit.tasks` and show the task breakdown +6. Execute one task with `/speckit.implement` + +### Connection to Other Challenges -Students working in `src/api/*.ts` now load: 400 + 250 + 200 = 850 tokens (vs. 1500 before) +- **Challenge 04 (Prompt Architecture):** Spec Kit is a formalized version of structured prompting +- **Challenge 06 (Token Golf):** Spec Kit naturally reduces tokens by eliminating context repetition +- **Challenge 07 (Infrastructure):** Constitution can encode infrastructure standards diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md index 929d4884e5..2609bcbc2b 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md @@ -1,49 +1,145 @@ -# Challenge 02 - Model Selection & Output Constraints - Coach's Guide +# Challenge 02 - Context Engineering - Coach's Guide [< Previous Solution](./Solution-01.md) - **[Home](./README.md)** - [Next Solution >](./Solution-03.md) ## Notes & Guidance -This challenge demonstrates that credit cost depends on both model selection and output volume. A cheaper model with tight constraints often beats an expensive model with verbose output. +This challenge teaches students that persistent context has recurring costs. The goal is to minimize always-on overhead while maintaining quality through scoped instructions and precise attachments. ### Key Concepts to Explain -**Model Pricing Hierarchy (Approximate):** -- GPT-4o class: ~1x baseline cost -- Claude Sonnet: ~1x baseline cost -- Claude Haiku: ~0.1x baseline cost (10x cheaper) +**The Three Types of Context Costs:** -**Output constraints as cost controls:** -- "Output code only" eliminates explanation tokens -- JSON schema constrains response format -- Word limits ("explain in <50 words") cap verbosity -- Structured output prevents rambling +1. **Persistent Instructions (recurring cost):** + - `.github/copilot-instructions.md` loads on EVERY interaction + - Example: 1500-token global file = 1500 tokens × every chat/edit call + - Target: keep global instructions under 500-1000 tokens -### Key Data Points to Share +2. **GitHub Copilot Skills (conditional cost):** + - Only load when explicitly invoked + - Example: `@workspace /new` only loads creation templates when called + - Best for: task-specific patterns that don't apply to all work -**Real-world comparison:** -- Regular Agent Mode (Sonnet): ~65 credits for a moderate task -- Custom Agent (Haiku) with "code only" constraint: ~7.6 credits for same task -- Savings: 88% reduction by choosing cheaper model + output constraints +3. **Attachments (per-call cost):** + - You control exactly what's included each time + - Example: `#file:src/api/routes.ts` only loads when you attach it + - `#Codebase` can pull in thousands of unnecessary tokens -**When to use each model:** -- Haiku: Boilerplate, refactoring, well-defined tasks -- Sonnet/GPT-4: Complex logic, architecture decisions, debugging novel issues -- Auto mode: Let GitHub Copilot route based on complexity (10% discount for cache-aware routing) +### Part A: Instruction Scoping Strategy + +**Audit Process:** + +Help students categorize their bloated instructions: + +- **Keep Global (under 500 tokens):** + - Code style preferences that apply universally (e.g., "prefer functional patterns") + - Quality standards (e.g., "always handle errors explicitly") + - Organization-wide conventions + +- **Move to Language-Specific:** + - `.github/copilot-instructions-python.md` for Python-only rules + - `.github/copilot-instructions-typescript.md` for TypeScript-only rules + - These only load when working in that language + +- **Move to Path-Specific:** + - `src/api/.github/copilot-instructions.md` for API-specific patterns + - `tests/.github/copilot-instructions.md` for testing conventions + - These only load when working in that directory + +- **Convert to Skills:** + - Task-specific templates (e.g., "how to write a migration") + - Conditional patterns (e.g., "when adding a new model, do X") + +**Expected Savings:** + +- Before: ~1500 tokens per interaction (global instructions) +- After: ~400 tokens global + ~200 tokens scoped (only when in scope) +- Result: 60-70% reduction in instruction overhead for most interactions + +### Part B: Attachment Precision + +**Common Anti-Pattern:** + +``` +Prompt: "Refactor the authentication logic" +Attachments: #Codebase +``` +This pulls in everything—potentially 50,000+ tokens for a large repo. + +**Optimized Pattern:** + +``` +Prompt: "Refactor the authentication logic" +Attachments: + - #file:src/auth/middleware.ts:1-50 + - #file:src/auth/types.ts + - #file:tests/auth.test.ts +``` +This pulls in exactly what's needed—perhaps 500 tokens. + +**Demonstration Exercise:** + +Have students complete the same refactor twice: +1. With `#Codebase` (record token count from Output panel) +2. With pinned files (record token count) + +Typical results: 10,000+ tokens → 800 tokens (90%+ reduction) + +### Common Blockers + +**Students Don't Know What to Keep Global:** + +Rule of thumb: If a rule only applies to 20% of your codebase, it shouldn't be global. + +**Path-Specific Instructions Not Loading:** + +GitHub Copilot walks up the directory tree looking for `.github/copilot-instructions.md` files. Ensure: +- Directory structure is correct +- File is named exactly `.github/copilot-instructions.md` (not `.github/copilot-instructions-api.md` in the api folder) + +**Can't Measure Token Reduction:** + +- VS Code Output panel (View → Output → "GitHub Copilot Chat") shows token counts +- If not visible, update GitHub Copilot extension to latest version ### Expected Time -60 minutes: -- 20 minutes: Complete baseline task with 3+ different models -- 20 minutes: Apply output constraints to one model -- 20 minutes: Measure and document findings +60 minutes total: +- 20 minutes: Audit and categorize global instructions +- 20 minutes: Restructure into scoped files +- 20 minutes: Test attachment precision and measure savings ### Success Criteria Validation -Students should show credit cost comparison table across models and demonstrate measurable savings from output constraints. +Students should demonstrate: +- Global `.github/copilot-instructions.md` reduced to under 500 tokens +- At least one path-specific or language-specific instruction file created +- Token comparison showing savings from pinned attachments vs. `#Codebase` +- Same baseline task completed with reduced credit cost ### Hints to Share -- The fastest model isn't always the cheapest—total credits = input rate + output rate -- If your prompt is 1000 tokens and response is 500 tokens, output constraints save more than model switching -- Auto mode's 10% discount comes from cache-aware routing, but only when natural task boundaries align +- Start by asking: "Does this rule apply to ALL code I write?" If no, scope it +- Use language-specific files for linting/formatting rules that vary by language +- Use path-specific files for architectural patterns (e.g., API conventions in `src/api/`) +- Pin files when you know exactly what you need; use `#Codebase` only for discovery +- The goal isn't zero instructions—it's right-sized instructions + +### Reference Solutions + +Typical restructuring: + +**Before (1500 tokens global):** +``` +.github/copilot-instructions.md (all rules) +``` + +**After (400 tokens global + scoped):** +``` +.github/copilot-instructions.md (universal rules, ~400 tokens) +.github/copilot-instructions-python.md (Python-specific, ~300 tokens) +.github/copilot-instructions-typescript.md (TypeScript-specific, ~250 tokens) +src/api/.github/copilot-instructions.md (API patterns, ~200 tokens) +``` + +Students working in `src/api/*.ts` now load: 400 + 250 + 200 = 850 tokens (vs. 1500 before) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md index 98625d3dce..7d690a4d95 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md @@ -1,202 +1,49 @@ -# Challenge 03 - Session Configuration (Tools + Cache) - Coach's Guide +# Challenge 03 - Model Selection & Output Constraints - Coach's Guide [< Previous Solution](./Solution-02.md) - **[Home](./README.md)** - [Next Solution >](./Solution-04.md) ## Notes & Guidance -This challenge teaches students that MCP tools add token overhead on every request, and that configuration changes can invalidate cached context. The TypeScript repository scan scenario provides a simple, measurable task to observe these effects. +This challenge demonstrates that credit cost depends on both model selection and output volume. A cheaper model with tight constraints often beats an expensive model with verbose output. ### Key Concepts to Explain -**MCP Tool Overhead:** -- Each MCP tool's definition (name, description, parameter schema) is included in the system prompt -- This overhead applies to every LLM request, even if the tool is never invoked -- The GitHub MCP server typically enables 6-8 tools by default -- For the repository scan task, students likely only need `search_code` and `get_file_contents` -- Unused tools like `create_issue`, `search_users`, `list_pull_requests` add unnecessary overhead +**Model Pricing Hierarchy (Approximate):** +- GPT-4o class: ~1x baseline cost +- Claude Sonnet: ~1x baseline cost +- Claude Haiku: ~0.1x baseline cost (10x cheaper) -**Cache Invalidation:** -- GitHub Copilot CLI uses Anthropic Claude models with prompt caching -- Cache invalidation occurs when the system prompt changes (e.g., tool definitions, instructions) -- Common triggers: toggling MCP tools, editing `.github/copilot-instructions.md`, switching models -- Clean sessions maintain stable configuration = higher cache reuse = lower costs -- Messy sessions with mid-task changes = cache invalidation = reprocessing overhead +**Output constraints as cost controls:** +- "Output code only" eliminates explanation tokens +- JSON schema constrains response format +- Word limits ("explain in <50 words") cap verbosity +- Structured output prevents rambling -**Important Note on Documentation:** -GitHub's official documentation doesn't explicitly list cache invalidation triggers. Students discover these through experimentation by observing credit spikes after configuration changes. The underlying Anthropic prompt caching technology invalidates cache when the prompt prefix changes. +### Key Data Points to Share -### The Scenario +**Real-world comparison:** +- Regular Agent Mode (Sonnet): ~65 credits for a moderate task +- Custom Agent (Haiku) with "code only" constraint: ~7.6 credits for same task +- Savings: 88% reduction by choosing cheaper model + output constraints -Students use GitHub Copilot CLI to scan `microsoft/TypeScript` repository: -- Find all `package.json` files -- Find all `tsconfig.json` files -- Read main package.json for dependencies -- Generate a formatted report - -This is a multi-turn task (5-10 agent steps) that provides multiple measurement opportunities. +**When to use each model:** +- Haiku: Boilerplate, refactoring, well-defined tasks +- Sonnet/GPT-4: Complex logic, architecture decisions, debugging novel issues +- Auto mode: Let GitHub Copilot route based on complexity (10% discount for cache-aware routing) ### Expected Time 60 minutes: -- 15 minutes: Complete initial scan with all tools, record baseline -- 10 minutes: Identify unused tools via VS Code Output panel -- 15 minutes: Disable unused tools, repeat scan, measure savings -- 15 minutes: Clean vs. messy session comparison -- 5 minutes: Document findings - -### Expected Measurements - -**Tool Overhead Savings:** -- Baseline: 6-8 GitHub MCP tools enabled -- Optimized: 2 tools enabled (search_code, get_file_contents) -- Removed: 4-6 unused tools -- Each unused tool: ~100-300 tokens per agent step -- Scan task: ~5-10 agent steps -- **Expected savings: 2,000-15,000 tokens (20-150 credits)** - -Actual savings vary based on: -- Model selected (Sonnet vs Haiku have different base costs) -- Number of tools initially enabled -- Complexity of tool schemas -- Number of agent steps taken - -**Cache Invalidation Impact:** -- Clean session: Configure once, complete scan = stable cache -- Messy session: Toggle tool mid-scan + edit instructions = cache invalidations -- **Expected difference: 10-30% higher cost for messy session** - -The difference may be subtle since the scan task is relatively short. Longer tasks show more dramatic cache invalidation penalties. - -### Common Blockers - -**Students Can't Find MCP Tool Configuration:** -- MCP servers are configured in Copilot CLI settings (platform-specific) -- On macOS/Linux: `~/.copilot/mcp.json` or via CLI settings -- On Windows: `%USERPROFILE%\.copilot\mcp.json` -- Students can also use `copilot mcp` command to manage servers - -**Students Don't See Tool Invocations:** -- VS Code Output panel: View → Output → select "GitHub Copilot" from dropdown -- Tool calls appear as JSON-RPC messages showing tool name and parameters -- If no tools appear, they may not have GitHub MCP server configured -- Provide example output so they know what to look for - -**Students Can't Measure Credits Accurately:** -- Use `/usage` command after each task to see credit breakdown -- GitHub Copilot usage dashboard shows cumulative spend (may be delayed) -- Encourage students to record: task name, timestamp, credits used -- Focus on relative differences (before/after) rather than absolute numbers - -**Cache Invalidation Effects Are Subtle:** -- Short tasks may not show dramatic differences -- Encourage students to make obvious changes: toggle multiple tools, edit instructions significantly -- Credit spikes may be small (10-30%) but still measurable -- The learning goal is awareness of the pattern, not hitting specific numbers - -### Hints to Share - -**If students struggle to identify unused tools:** -- "Look for tools that never appear in the Output panel during your scan" -- "Ask yourself: did I create any issues? Did I search for users? If no, you don't need those tools" -- "For a read-only repository scan, you only need search and read tools" - -**If students can't see cache invalidation effects:** -- "Try making more dramatic changes mid-session—edit instructions significantly, toggle 2-3 tools" -- "The effect is more visible on longer tasks; your short scan may show smaller differences" -- "Focus on observing the pattern, not hitting a specific percentage" - -**If students question why this matters:** -- "In production, developers run hundreds of Copilot interactions per day" -- "Small per-request overhead × hundreds of requests = significant monthly cost" -- "Clean session hygiene is like good Git hygiene—prevents accumulated waste" - -### Technical Deep Dive (If Asked) - -**How MCP Tools Add Overhead:** - -From the Model Context Protocol specification, each tool includes: -```json -{ - "name": "get_weather", - "description": "Get current weather information for a location", - "inputSchema": { - "type": "object", - "properties": { - "location": { - "type": "string", - "description": "City name or zip code" - } - }, - "required": ["location"] - } -} -``` - -This full schema is sent to the LLM on every request so the model knows: -- What tools are available -- What each tool does -- How to call them correctly - -A simple tool uses ~100-150 tokens; complex tools with many parameters use 300-500+ tokens. - -**Why Cache Invalidation Happens:** - -GitHub Copilot CLI uses Anthropic Claude models. Anthropic's prompt caching works by caching the "prompt prefix" (system instructions + tool definitions + conversation history up to a cache marker). - -If anything in that prefix changes—even one token—the cache is invalidated and must be rebuilt. This means: -- Toggling a tool → system prompt changes → cache invalidated -- Editing instructions → system prompt changes → cache invalidated -- Switching models → different model has its own cache space - -Reference: [Anthropic Prompt Caching](https://claude.com/blog/prompt-caching) +- 20 minutes: Complete baseline task with 3+ different models +- 20 minutes: Apply output constraints to one model +- 20 minutes: Measure and document findings ### Success Criteria Validation -Students successfully complete when they can show: - -1. ✅ **Tool audit documentation:** - - Screenshot or text output showing enabled tools before optimization - - Evidence of which tools were actually invoked (VS Code Output panel) - - Screenshot showing reduced tool list after optimization - -2. ✅ **Measurable savings:** - - Credit spend for baseline scan (all tools enabled) - - Credit spend for optimized scan (unused tools disabled) - - Calculated savings (even if small) +Students should show credit cost comparison table across models and demonstrate measurable savings from output constraints. -3. ✅ **Cache invalidation observation:** - - Credit spend for clean session - - Credit spend for messy session - - Description of which changes they made mid-session - - Observation that messy session cost more - -4. ✅ **Learning articulation:** - - Can explain why unused tools cost tokens - - Can name at least 2-3 configuration changes that invalidate cache - - Understands that stable configuration = better cache reuse - -### Extension Challenges - -For teams that finish early: - -**Advanced Tool Audit:** -- Configure 3-4 different MCP servers (GitHub, filesystem, HTTP, database) -- Complete a task using only one server -- Measure overhead from all the extra unused servers - -**Model Comparison:** -- Complete the scan with Sonnet (all tools) vs Haiku (minimal tools) -- Observe that cheaper model + clean config can beat expensive model + bloated config - -**Long Session Test:** -- Use Copilot CLI for 30+ minutes of varied tasks -- Observe compaction behavior when context window fills (~80% capacity) -- Measure whether frequent configuration changes trigger more compaction - -### Additional Resources for Students - -Share after they complete the challenge: +### Hints to Share -- [Managing Context in GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/context-management) - Official docs on context window and compaction -- [MCP Tools Specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools.md) - Details on what's included in tool schemas -- Research report saved during hack preparation with detailed citations and technical validation +- The fastest model isn't always the cheapest—total credits = input rate + output rate +- If your prompt is 1000 tokens and response is 500 tokens, output constraints save more than model switching +- Auto mode's 10% discount comes from cache-aware routing, but only when natural task boundaries align diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md index c21bbb1efe..8166ef126b 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md @@ -1,44 +1,202 @@ -# Challenge 04 - Context Window Management - Coach's Guide +# Challenge 04 - Session Configuration (Tools + Cache) - Coach's Guide [< Previous Solution](./Solution-03.md) - **[Home](./README.md)** - [Next Solution >](./Solution-05.md) ## Notes & Guidance -This challenge teaches proactive context management vs. reactive recovery. The biggest avoidable cost is not running `/compact` until context rot has already degraded quality. +This challenge teaches students that MCP tools add token overhead on every request, and that configuration changes can invalidate cached context. The TypeScript repository scan scenario provides a simple, measurable task to observe these effects. ### Key Concepts to Explain -**Context Rot Timeline:** -- 0-60% capacity: Quality remains high -- 60-70% capacity: First signs of degradation (inconsistencies) -- 70-85% capacity: Noticeable quality loss, forgotten requirements -- 85-100% capacity: Severe degradation, expensive recovery loops +**MCP Tool Overhead:** +- Each MCP tool's definition (name, description, parameter schema) is included in the system prompt +- This overhead applies to every LLM request, even if the tool is never invoked +- The GitHub MCP server typically enables 6-8 tools by default +- For the repository scan task, students likely only need `search_code` and `get_file_contents` +- Unused tools like `create_issue`, `search_users`, `list_pull_requests` add unnecessary overhead -**Two Commands, Different Purposes:** -- `/compact`: Summarizes previous work, preserves state, preserves cache (steering wheel) -- `/clear`: Wipes everything, cold cache restart (reset button) +**Cache Invalidation:** +- GitHub Copilot CLI uses Anthropic Claude models with prompt caching +- Cache invalidation occurs when the system prompt changes (e.g., tool definitions, instructions) +- Common triggers: toggling MCP tools, editing `.github/copilot-instructions.md`, switching models +- Clean sessions maintain stable configuration = higher cache reuse = lower costs +- Messy sessions with mid-task changes = cache invalidation = reprocessing overhead -**Natural Breakpoints for Compaction:** -- Feature complete and tests passing -- Architecture decision made -- Switching to new topic/module -- Before context hits 60% utilization +**Important Note on Documentation:** +GitHub's official documentation doesn't explicitly list cache invalidation triggers. Students discover these through experimentation by observing credit spikes after configuration changes. The underlying Anthropic prompt caching technology invalidates cache when the prompt prefix changes. + +### The Scenario + +Students use GitHub Copilot CLI to scan `microsoft/TypeScript` repository: +- Find all `package.json` files +- Find all `tsconfig.json` files +- Read main package.json for dependencies +- Generate a formatted report + +This is a multi-turn task (5-10 agent steps) that provides multiple measurement opportunities. ### Expected Time -45 minutes: -- 15 minutes: Observe context rot (Part A) -- 20 minutes: Demonstrate proactive compaction (Part B) -- 10 minutes: Document findings +60 minutes: +- 15 minutes: Complete initial scan with all tools, record baseline +- 10 minutes: Identify unused tools via VS Code Output panel +- 15 minutes: Disable unused tools, repeat scan, measure savings +- 15 minutes: Clean vs. messy session comparison +- 5 minutes: Document findings -### Success Criteria Validation +### Expected Measurements + +**Tool Overhead Savings:** +- Baseline: 6-8 GitHub MCP tools enabled +- Optimized: 2 tools enabled (search_code, get_file_contents) +- Removed: 4-6 unused tools +- Each unused tool: ~100-300 tokens per agent step +- Scan task: ~5-10 agent steps +- **Expected savings: 2,000-15,000 tokens (20-150 credits)** + +Actual savings vary based on: +- Model selected (Sonnet vs Haiku have different base costs) +- Number of tools initially enabled +- Complexity of tool schemas +- Number of agent steps taken + +**Cache Invalidation Impact:** +- Clean session: Configure once, complete scan = stable cache +- Messy session: Toggle tool mid-scan + edit instructions = cache invalidations +- **Expected difference: 10-30% higher cost for messy session** + +The difference may be subtle since the scan task is relatively short. Longer tasks show more dramatic cache invalidation penalties. + +### Common Blockers + +**Students Can't Find MCP Tool Configuration:** +- MCP servers are configured in Copilot CLI settings (platform-specific) +- On macOS/Linux: `~/.copilot/mcp.json` or via CLI settings +- On Windows: `%USERPROFILE%\.copilot\mcp.json` +- Students can also use `copilot mcp` command to manage servers -Students should demonstrate measurable quality degradation after 70% context utilization and show credit savings from proactive `/compact` vs. letting context rot. +**Students Don't See Tool Invocations:** +- VS Code Output panel: View → Output → select "GitHub Copilot" from dropdown +- Tool calls appear as JSON-RPC messages showing tool name and parameters +- If no tools appear, they may not have GitHub MCP server configured +- Provide example output so they know what to look for + +**Students Can't Measure Credits Accurately:** +- Use `/usage` command after each task to see credit breakdown +- GitHub Copilot usage dashboard shows cumulative spend (may be delayed) +- Encourage students to record: task name, timestamp, credits used +- Focus on relative differences (before/after) rather than absolute numbers + +**Cache Invalidation Effects Are Subtle:** +- Short tasks may not show dramatic differences +- Encourage students to make obvious changes: toggle multiple tools, edit instructions significantly +- Credit spikes may be small (10-30%) but still measurable +- The learning goal is awareness of the pattern, not hitting specific numbers ### Hints to Share -- Context window utilization visible in VS Code status bar or Output panel -- Run `/compact` before you feel the pain, not after -- Natural breakpoints: "I just finished X, now starting Y"—compact at the transition -- `/compact` preserves cache; `/clear` forces cold restart -- The cost isn't running `/compact` too often—it's running it too late +**If students struggle to identify unused tools:** +- "Look for tools that never appear in the Output panel during your scan" +- "Ask yourself: did I create any issues? Did I search for users? If no, you don't need those tools" +- "For a read-only repository scan, you only need search and read tools" + +**If students can't see cache invalidation effects:** +- "Try making more dramatic changes mid-session—edit instructions significantly, toggle 2-3 tools" +- "The effect is more visible on longer tasks; your short scan may show smaller differences" +- "Focus on observing the pattern, not hitting a specific percentage" + +**If students question why this matters:** +- "In production, developers run hundreds of Copilot interactions per day" +- "Small per-request overhead × hundreds of requests = significant monthly cost" +- "Clean session hygiene is like good Git hygiene—prevents accumulated waste" + +### Technical Deep Dive (If Asked) + +**How MCP Tools Add Overhead:** + +From the Model Context Protocol specification, each tool includes: +```json +{ + "name": "get_weather", + "description": "Get current weather information for a location", + "inputSchema": { + "type": "object", + "properties": { + "location": { + "type": "string", + "description": "City name or zip code" + } + }, + "required": ["location"] + } +} +``` + +This full schema is sent to the LLM on every request so the model knows: +- What tools are available +- What each tool does +- How to call them correctly + +A simple tool uses ~100-150 tokens; complex tools with many parameters use 300-500+ tokens. + +**Why Cache Invalidation Happens:** + +GitHub Copilot CLI uses Anthropic Claude models. Anthropic's prompt caching works by caching the "prompt prefix" (system instructions + tool definitions + conversation history up to a cache marker). + +If anything in that prefix changes—even one token—the cache is invalidated and must be rebuilt. This means: +- Toggling a tool → system prompt changes → cache invalidated +- Editing instructions → system prompt changes → cache invalidated +- Switching models → different model has its own cache space + +Reference: [Anthropic Prompt Caching](https://claude.com/blog/prompt-caching) + +### Success Criteria Validation + +Students successfully complete when they can show: + +1. ✅ **Tool audit documentation:** + - Screenshot or text output showing enabled tools before optimization + - Evidence of which tools were actually invoked (VS Code Output panel) + - Screenshot showing reduced tool list after optimization + +2. ✅ **Measurable savings:** + - Credit spend for baseline scan (all tools enabled) + - Credit spend for optimized scan (unused tools disabled) + - Calculated savings (even if small) + +3. ✅ **Cache invalidation observation:** + - Credit spend for clean session + - Credit spend for messy session + - Description of which changes they made mid-session + - Observation that messy session cost more + +4. ✅ **Learning articulation:** + - Can explain why unused tools cost tokens + - Can name at least 2-3 configuration changes that invalidate cache + - Understands that stable configuration = better cache reuse + +### Extension Challenges + +For teams that finish early: + +**Advanced Tool Audit:** +- Configure 3-4 different MCP servers (GitHub, filesystem, HTTP, database) +- Complete a task using only one server +- Measure overhead from all the extra unused servers + +**Model Comparison:** +- Complete the scan with Sonnet (all tools) vs Haiku (minimal tools) +- Observe that cheaper model + clean config can beat expensive model + bloated config + +**Long Session Test:** +- Use Copilot CLI for 30+ minutes of varied tasks +- Observe compaction behavior when context window fills (~80% capacity) +- Measure whether frequent configuration changes trigger more compaction + +### Additional Resources for Students + +Share after they complete the challenge: + +- [Managing Context in GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/context-management) - Official docs on context window and compaction +- [MCP Tools Specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools.md) - Details on what's included in tool schemas +- Research report saved during hack preparation with detailed citations and technical validation diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md index fb0a8039e4..27d2a4afae 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md @@ -1,169 +1,44 @@ -# Challenge 05 - Spec-Driven Development with Spec Kit - Coach's Guide +# Challenge 05 - Context Window Management - Coach's Guide [< Previous Solution](./Solution-04.md) - **[Home](./README.md)** - [Next Solution >](./Solution-06.md) ## Notes & Guidance -This challenge introduces students to **spec-driven development** by having them build the **same simple application twice**: first with ad-hoc prompting, then with **GitHub Spec Kit**. The hands-on comparison makes the benefits tangible. - -> **Note:** Spec Kit installation prerequisites are covered in Challenge 0. If students haven't completed setup, direct them there first. - -### The Application - -Students build a **simple notes app** with only 2 requirements: -1. CRUD operations for notes -2. Each note has a title (required) and content - -This is intentionally simple — the goal is to compare approaches, not build something complex. +This challenge teaches proactive context management vs. reactive recovery. The biggest avoidable cost is not running `/compact` until context rot has already degraded quality. ### Key Concepts to Explain -**Why Two Applications?** - -Building the same thing twice demonstrates: -- How much context repetition happens with ad-hoc prompting -- How structured specs reduce cognitive load and token usage -- The difference in output consistency - -**Part 1 is Intentionally Unguided:** - -Students don't get example prompts — they figure it out themselves. This: -- Creates authentic frustration with ad-hoc prompting -- Makes the Spec Kit workflow feel like a relief -- Produces genuine observations for comparison - -**Spec Kit is One Approach:** - -Emphasize that Spec Kit is **one of many** ways to do spec-driven development. The principle — structured context produces better results — applies regardless of tooling. Other approaches include: -- Custom instruction files (.github/copilot-instructions.md) -- Manual spec documents referenced in prompts -- Project constitution patterns -- Prompt template systems - -**Spec Kit Workflow:** - -1. **Constitution:** Project-wide rules and constraints (architecture, standards, patterns) -2. **Spec:** What to build (requirements, acceptance criteria, user stories) -3. **Plan:** How to build it (architecture, stack, structure) -4. **Tasks:** Actionable work items (small, ordered, executable) -5. **Implement:** Execute tasks with Copilot +**Context Rot Timeline:** +- 0-60% capacity: Quality remains high +- 60-70% capacity: First signs of degradation (inconsistencies) +- 70-85% capacity: Noticeable quality loss, forgotten requirements +- 85-100% capacity: Severe degradation, expensive recovery loops -**Why This Reduces Cost:** +**Two Commands, Different Purposes:** +- `/compact`: Summarizes previous work, preserves state, preserves cache (steering wheel) +- `/clear`: Wipes everything, cold cache restart (reset button) -- Spec becomes persistent context — no need to repeat in every prompt -- Constitution provides guardrails that apply automatically -- Structured workflow prevents expensive backtracking -- Small tasks produce more predictable outputs than large prompts -- Clarification step catches ambiguity before implementation +**Natural Breakpoints for Compaction:** +- Feature complete and tests passing +- Architecture decision made +- Switching to new topic/module +- Before context hits 60% utilization ### Expected Time -45-75 minutes: -- 15-20 minutes: Part 1 — Build with ad-hoc prompting -- 20-30 minutes: Part 2 — Build with Spec Kit workflow -- 10-15 minutes: Part 3 — Compare results and discussion - -### Troubleshooting - -**Spec Kit Commands Not Appearing in Copilot Chat:** - -1. Verify `.github/prompts/` folder exists with Spec Kit files -2. Reload VS Code window (Ctrl+Shift+P → "Developer: Reload Window") -3. Ensure Copilot Chat extension is up to date - -**Integration Issues:** - -If `--integration copilot` fails, try initializing without integration first: -```bash -uvx --from git+https://github.com/github/spec-kit.git specify init my-project -``` -Then manually copy prompt files to `.github/prompts/`. +45 minutes: +- 15 minutes: Observe context rot (Part A) +- 20 minutes: Demonstrate proactive compaction (Part B) +- 10 minutes: Document findings ### Success Criteria Validation -Students should be able to demonstrate: - -**Part 1 — Ad-Hoc Approach:** -1. Created task-api-adhoc project -2. Built the API using conversational prompts -3. Documented observations (context repetition, inconsistencies) - -**Part 2 — Spec Kit Approach:** -1. **Setup Complete:** `.specify/` and `.github/prompts/` folders exist -2. **Constitution Created:** `constitution.md` with project rules -3. **Spec Generated:** `spec.md` with requirements and acceptance criteria -4. **Plan Produced:** Architecture and structure decisions documented -5. **Tasks Listed:** Ordered list of small, actionable items -6. **Implementation Started:** At least one task executed with Copilot - -**Part 3 — Comparison:** -1. Completed the comparison table -2. Can articulate differences between approaches -3. Understands why structured specs reduce token usage - -### Common Blockers - -**Students Skip Steps:** - -Emphasize the workflow is sequential by design. Each step builds on the previous. Skipping to `/speckit.implement` without a spec produces the same results as ad-hoc prompting. - -**Vague Constitution:** - -Guide them to be specific. Bad: "Good code." Good: "Node.js with TypeScript, Express framework, repository pattern, input validation with Joi." - -**Spec Too Large:** - -If the spec covers too much, `/speckit.plan` and `/speckit.tasks` become unwieldy. Encourage smaller, focused specs for individual features. - -**Students Want to Edit Generated Files:** - -This is fine! The generated specs/plans are starting points. Encourage editing for accuracy before proceeding. +Students should demonstrate measurable quality degradation after 70% context utilization and show credit savings from proactive `/compact` vs. letting context rot. ### Hints to Share -- Use `/speckit.clarify` whenever you feel the spec is ambiguous — it's designed to ask the right questions -- The constitution applies to everything — write it once, benefit everywhere -- Review the plan before generating tasks — it's easier to fix architecture issues at the plan stage -- Tasks should be small enough to complete in a single Copilot interaction -- You can re-run any command to regenerate — the workflow is iterative - -### Reflection Discussion Points - -After completion, discuss with students: - -1. **Experience Difference:** How did Part 1 feel compared to Part 2? -2. **Context Repetition:** How many times did they repeat requirements in each approach? -3. **Consistency:** Was the Spec Kit output more predictable? -4. **Token Impact:** Fewer retries, less context repetition = lower token usage -5. **Other Approaches:** What other methods could achieve similar structured benefits? - -### Key Insight for Students - -> **Spec becomes your context. Not the chat.** - -Traditional prompting requires repeating context every time. With Spec Kit, the spec IS the context that Copilot references. This is both better engineering and better token economics. - -### Coaching Part 1 (Ad-Hoc) - -Let students experience the frustration! Don't intervene too quickly. Common observations: -- They had to repeat "use Node.js" multiple times -- Copilot "forgot" earlier requirements -- Code style was inconsistent between prompts -- They felt like they were re-explaining constantly - -This pain is what makes Part 2 powerful. - -### Demo Script (If Students Struggle) - -1. Initialize project: Show the generated folder structure -2. Run `/speckit.constitution` and show resulting file -3. Run `/speckit.specify` with a simple requirement -4. Show how `/speckit.plan` produces architecture from the spec -5. Run `/speckit.tasks` and show the task breakdown -6. Execute one task with `/speckit.implement` - -### Connection to Other Challenges - -- **Challenge 04 (Prompt Architecture):** Spec Kit is a formalized version of structured prompting -- **Challenge 06 (Token Golf):** Spec Kit naturally reduces tokens by eliminating context repetition -- **Challenge 07 (Infrastructure):** Constitution can encode infrastructure standards +- Context window utilization visible in VS Code status bar or Output panel +- Run `/compact` before you feel the pain, not after +- Natural breakpoints: "I just finished X, now starting Y"—compact at the transition +- `/compact` preserves cache; `/clear` forces cold restart +- The cost isn't running `/compact` too often—it's running it too late diff --git a/xxx-GitHubCopilotCostOptimization/README.md b/xxx-GitHubCopilotCostOptimization/README.md index 3fa6491c71..f57ec91e69 100644 --- a/xxx-GitHubCopilotCostOptimization/README.md +++ b/xxx-GitHubCopilotCostOptimization/README.md @@ -21,16 +21,16 @@ In this hack, you will learn practical techniques to optimize GitHub Copilot usa - Challenge 00: **[Prerequisites](Student/Challenge-00.md)** - Set up the hack environment -- Challenge 01: **[Context Engineering](Student/Challenge-01.md)** +- Challenge 01: **[Spec-Driven Development](Student/Challenge-01.md)** + - Demonstrate that deterministic controls (tests, specs) reduce trial-and-error token burn +- Challenge 02: **[Context Engineering](Student/Challenge-02.md)** - Audit and restructure global instructions into scoped files, and replace broad references with pinned attachments -- Challenge 02: **[Model Selection & Output Constraints](Student/Challenge-02.md)** +- Challenge 03: **[Model Selection & Output Constraints](Student/Challenge-03.md)** - Compare credit costs across models and reasoning levels, and apply output constraints to reduce token spend -- Challenge 03: **[Session Configuration (Tools + Cache)](Student/Challenge-03.md)** +- Challenge 04: **[Session Configuration (Tools + Cache)](Student/Challenge-04.md)** - Prune unused MCP tools and understand cache invalidation patterns -- Challenge 04: **[Context Window Management](Student/Challenge-04.md)** +- Challenge 05: **[Context Window Management](Student/Challenge-05.md)** - Use /compact proactively to manage growing context windows and avoid context rot -- Challenge 05: **[Spec-Driven Development](Student/Challenge-05.md)** - - Demonstrate that deterministic controls (tests, specs) reduce trial-and-error token burn - Challenge 06: **[Token Golf Competition](Student/Challenge-06.md)** - Complete a coding task with the lowest credit spend while meeting all acceptance criteria diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md index 044dcb403d..634b841e21 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md @@ -1,57 +1,275 @@ -# Challenge 01 - Context Engineering +# Challenge 01 - Spec-Driven Development with Spec Kit [< Previous Challenge](./Challenge-00.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-02.md) ## Introduction -Every token sent to GitHub Copilot has a cost. Context that persists across every interaction—like global `.github/copilot-instructions.md` files—creates recurring costs that compound quickly. Meanwhile, broad workspace references like `#Codebase` pull in unnecessary files, adding tokens you don't need. +In this challenge, you will experience the difference between **ad-hoc prompting** and **spec-driven development** by building the same application twice — first without structure, then using **GitHub Spec Kit**. -In this challenge, you'll learn to engineer your context precisely. You'll audit an over-stuffed global instructions file, restructure it into scoped path-specific files, and replace broad references with pinned attachments. The goal: reduce the base cost of every Copilot interaction while maintaining quality. +Spec Kit is one of several ways to implement spec-driven development with GitHub Copilot. The core principle applies regardless of tooling: **structured context produces better results than conversational prompts**. + +With Spec Kit, you will: + +- Define a **constitution (rules)** +- Create a **spec (what to build)** +- Generate a **plan (how to build)** +- Break it into **tasks** +- Execute implementation + +**Goal:** Experience firsthand how structured specs reduce token usage and improve output quality compared to ad-hoc prompting. + +> **Key Concept:** Spec becomes your context. Not the chat. ## Description -The starter codebase includes an intentionally bloated `.github/copilot-instructions.md` file that loads on every GitHub Copilot interaction. Your challenge is to reduce the base cost of every interaction through context optimization. +In this challenge, you will build **the same application twice**: + +1. **Part 1:** Build with ad-hoc prompting (no structure) +2. **Part 2:** Build with Spec Kit workflow + +Then compare the results. + +### The Application + +You will build: + +> **A simple notes application** + +Requirements: +1. Create, read, update, and delete notes (CRUD) +2. Each note must have a title (required) and content + +That's it — keep it simple! + +--- + +## Part 1 — Build with Ad-Hoc Prompting + +First, build the application using traditional conversational prompting with Copilot. + +### Step 1 — Create a New Project Folder + +```bash +mkdir notes-app-adhoc +cd notes-app-adhoc +code . +``` + +### Step 2 — Build the Application + +Your goal: Create a working notes application that meets the 2 requirements above. + +**Rules:** +- Use only Copilot Chat with ad-hoc prompts +- No pre-written specs or documentation +- Just start prompting and see what happens + +**Try to complete the application on your own!** + +### Step 3 — Track Your Experience + +As you work, note: +- How many prompts did you need? +- How many times did you repeat the same information? +- Did Copilot "forget" what you asked earlier? +- Was the generated code consistent in style? +- How did it feel? + +### Step 4 — Save Your Results + +Keep this project. You'll compare it later. + +--- + +## Part 2 — Build with Spec Kit + +Now build the **same application** using the Spec Kit workflow. + +### Step 1 — Initialize a New Spec Kit Project + +```bash +specify init notes-app-speckit --integration copilot +cd notes-app-speckit +code . +``` + +### Step 2 — Verify Spec Kit is Ready + +In the project folder, you should see: +- `.specify/` +- `.github/prompts/` +- Markdown files + +In Copilot Chat, type `/` — you should see: +- `/speckit.constitution` +- `/speckit.specify` +- `/speckit.plan` +- `/speckit.tasks` +- `/speckit.implement` + +### Step 3 — Define Constitution + +In Copilot Chat, run: -### Instruction Scoping +``` +/speckit.constitution +``` -Audit the global instructions file and restructure it for efficiency: +Then describe your rules. Example: -- Identify which rules apply universally vs. only to specific languages or directories -- Minimize the global file by moving scoped rules to appropriate locations -- Consider converting task-specific patterns to GitHub Copilot Skills that activate conditionally -- Discover how language-specific and path-specific instruction files work +``` +Simple local application. Clean code with clear separation of concerns. +``` -### Attachment Precision +This creates the `constitution.md` file containing your system rules. -Experiment with workspace references to understand their token cost: +### Step 4 — Create Spec -- Compare using `#Codebase` vs. pinning specific files for the same coding task -- Measure the token difference between broad and precise attachment strategies -- Verify that output quality remains equivalent with more precise attachments +Run: -Use the baseline coding task from Challenge 00 to measure the impact of your optimizations. Compare credit consumption before and after restructuring to demonstrate measurable savings. +``` +/speckit.specify +``` + +Describe the same requirements as Part 1: + +``` +A notes application with CRUD operations. +Each note has a title (required) and content. +``` + +This creates a `spec.md` file with: +- Requirements +- Acceptance criteria +- User stories + +### Step 5 — (Optional) Clarify + +Run: + +``` +/speckit.clarify +``` + +Spec Kit will ask clarifying questions to improve your spec. This: +- Reduces ambiguity +- Reduces rework later + +### Step 6 — Generate Plan + +Run: + +``` +/speckit.plan +``` + +This generates: +- Architecture decisions +- Technology stack +- Project structure + +### Step 7 — Generate Tasks + +Run: + +``` +/speckit.tasks +``` + +This creates: +- List of small, actionable tasks +- Execution order + +### Step 8 — Implement + +Run: + +``` +/speckit.implement +``` + +Now Copilot will: +- Execute tasks sequentially +- Generate code incrementally + +--- + +## Part 3 — Compare Results + +Now compare both implementations. + +### Questions to Answer + +| Aspect | Ad-Hoc Approach | Spec Kit Approach | +|--------|-----------------|-------------------| +| Total prompts needed | ? | ? | +| Times you repeated context | ? | ? | +| Code consistency | ? | ? | +| Time to complete | ? | ? | +| Quality of output | ? | ? | + +### What to Look For + +- **Context retention:** Did Copilot remember requirements? +- **Consistency:** Did the code follow the same patterns throughout? +- **Completeness:** Were all requirements addressed? +- **Token efficiency:** How much did you have to type? + +## Rules + +- Complete Part 1 before starting Part 2 +- Do NOT skip steps in the Spec Kit workflow +- Review each output before continuing +- Make minimal edits — avoid rewriting everything +- Document your observations for comparison ## Success Criteria To complete this challenge successfully, you should be able to: -- Demonstrate that your restructured global `.github/copilot-instructions.md` is significantly smaller than the original -- Show path-specific or language-specific instruction files you created with rules moved from the global file -- Verify that at least one task-specific pattern has been converted to a GitHub Copilot Skill -- Show token count comparison between using `#Codebase` vs. pinned file attachments for a specific task -- Demonstrate measurable credit reduction on the baseline coding task -- Verify that code quality remained equivalent after optimization +- Build the task management API using ad-hoc prompting +- Build the same API using Spec Kit workflow +- Create a constitution that defines project rules and standards +- Generate a spec from your requirements description +- Produce a structured plan from the spec +- Break the plan into executable tasks +- Compare both approaches and articulate the differences +- Demonstrate reduced token usage with spec-driven development +- Show improved output consistency and predictability ## Learning Resources -- [GitHub Copilot Instructions Documentation](https://docs.github.com/en/copilot/customizing-copilot/adding-custom-instructions-for-github-copilot) -- [GitHub Copilot Skills Overview](https://docs.github.com/en/copilot/using-github-copilot/using-github-copilot-skills) -- [Understanding Context Windows in Large Language Models](https://www.anthropic.com/index/prompting-long-context) +- [GitHub Spec Kit Repository](https://github.com/github/spec-kit) +- [Spec Kit Installation Guide](https://github.com/github/spec-kit/blob/main/docs/installation.md) +- [Spec-Driven Development with GitHub Spec Kit](https://medium.com/@vamshi.rapolu/spec-driven-development-with-github-spec-kit-copilot-in-vs-code-new-existing-projects-2531d10bd61d) +- [Spec Kit Commands Reference](https://easyguides.net/guides/spec-kit/commands) +- [Plan and Tasks Commands Tutorial](https://codestandup.com/posts/2025/github-spec-kit-tutorial-plan-tasks-commands/) ## Tips -- Persistent instructions are recurring costs—they load on every call -- Skills are conditional costs—they only load when invoked -- Attachments are per-call costs—you control exactly what's included -- The engineering target: keep always-on global instructions under 1000 tokens -- Scoped instructions should be discoverable: if a rule only applies to `/api`, put the instruction file in `/api/.github/` +- Part 1 intentionally feels inefficient — that's the point! +- Spec becomes your persistent context — no need to repeat requirements +- The constitution acts as guardrails that apply to all generated code +- Use `/speckit.clarify` when requirements feel ambiguous +- Each step builds on the previous — the workflow is designed to be sequential +- Review generated specs and plans before proceeding to catch issues early +- Small, focused specs produce better results than large, vague ones + +## Reflection Questions + +After completing this challenge, answer: + +1. How did Part 1 (ad-hoc) feel compared to Part 2 (Spec Kit)? +2. How many times did you repeat context in each approach? +3. Did the outputs become more predictable with Spec Kit? +4. How would spec-driven development impact token usage and costs in real projects? +5. What other tools or methods could achieve similar spec-driven benefits? + +## Advanced Challenges + +Too comfortable? Try these: + +- Apply Spec Kit to an existing project instead of a new one +- Create multiple specs for different features and observe how they interact +- Measure credit consumption between both approaches for the same feature +- Customize the constitution for different project types (frontend, backend, full-stack) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md index a7429e23d0..62780f7f4c 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md @@ -1,50 +1,57 @@ -# Challenge 02 - Model Selection & Output Constraints +# Challenge 02 - Context Engineering [< Previous Challenge](./Challenge-01.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-03.md) ## Introduction -Not all tasks need the most powerful model. A cheaper model with tight output constraints can often outperform an expensive model that produces verbose responses. In this challenge, you'll learn to match models to task complexity and apply output constraints that reduce token generation without sacrificing quality. +Every token sent to GitHub Copilot has a cost. Context that persists across every interaction—like global `.github/copilot-instructions.md` files—creates recurring costs that compound quickly. Meanwhile, broad workspace references like `#Codebase` pull in unnecessary files, adding tokens you don't need. -The key insight: credit cost = (input tokens × input rate) + (output tokens × output rate). While you control input through context engineering, output constraints are your lever for controlling what the model generates. +In this challenge, you'll learn to engineer your context precisely. You'll audit an over-stuffed global instructions file, restructure it into scoped path-specific files, and replace broad references with pinned attachments. The goal: reduce the base cost of every Copilot interaction while maintaining quality. ## Description -Complete the same coding task from your baseline using different GitHub Copilot models and configurations. Your goal is to understand the cost-quality tradeoff and discover when cheaper models with constraints beat expensive models without them. +The starter codebase includes an intentionally bloated `.github/copilot-instructions.md` file that loads on every GitHub Copilot interaction. Your challenge is to reduce the base cost of every interaction through context optimization. -### Model Comparison +### Instruction Scoping -Experiment with the available models in your GitHub Copilot configuration (GPT-4o, Claude Sonnet, Claude Haiku if available, etc.). Complete your baseline coding task with different models and record the total credits consumed, output quality, iteration count, and response verbosity for each. +Audit the global instructions file and restructure it for efficiency: -### Reasoning Levels +- Identify which rules apply universally vs. only to specific languages or directories +- Minimize the global file by moving scoped rules to appropriate locations +- Consider converting task-specific patterns to GitHub Copilot Skills that activate conditionally +- Discover how language-specific and path-specific instruction files work -Explore how different reasoning levels affect credit utilization +### Attachment Precision -### Auto Mode +Experiment with workspace references to understand their token cost: -If GitHub Copilot's Auto mode is available, try it on the same task. Observe which models it selects for different subtasks, when it leverages cache, and how total cost compares to manual model selection. Understand the tradeoffs of automatic routing vs. manual control. +- Compare using `#Codebase` vs. pinning specific files for the same coding task +- Measure the token difference between broad and precise attachment strategies +- Verify that output quality remains equivalent with more precise attachments + +Use the baseline coding task from Challenge 00 to measure the impact of your optimizations. Compare credit consumption before and after restructuring to demonstrate measurable savings. ## Success Criteria To complete this challenge successfully, you should be able to: -- Demonstrate completion of the baseline task using multiple different models -- Show measured credit costs for each model with comparable input conditions -- Verify that output quality met acceptance criteria across model tests -- Demonstrate credit cost reduction from applying output constraints -- Show comparative data proving that a cheaper model with constraints can beat an expensive model without constraints -- Explain when Auto mode provides value vs. manual model selection +- Demonstrate that your restructured global `.github/copilot-instructions.md` is significantly smaller than the original +- Show path-specific or language-specific instruction files you created with rules moved from the global file +- Verify that at least one task-specific pattern has been converted to a GitHub Copilot Skill +- Show token count comparison between using `#Codebase` vs. pinned file attachments for a specific task +- Demonstrate measurable credit reduction on the baseline coding task +- Verify that code quality remained equivalent after optimization ## Learning Resources -- [GitHub Copilot Model Selection Guide](https://docs.github.com/en/copilot) -- [Prompt Engineering: Output Formatting Techniques](https://www.promptingguide.ai/) -- [Understanding Model Pricing and Token Rates](https://docs.github.com/en/copilot/about-github-copilot) +- [GitHub Copilot Instructions Documentation](https://docs.github.com/en/copilot/customizing-copilot/adding-custom-instructions-for-github-copilot) +- [GitHub Copilot Skills Overview](https://docs.github.com/en/copilot/using-github-copilot/using-github-copilot-skills) +- [Understanding Context Windows in Large Language Models](https://www.anthropic.com/index/prompting-long-context) ## Tips -- Input tokens are cheaper than output tokens for most models -- Verbose explanations cost credits—request code-only output when you don't need narration -- Haiku-class models can be significantly cheaper than Sonnet/GPT-4 class models -- Auto mode's discount comes from cache-aware routing, but only when task boundaries align with cache boundaries -- The best model isn't always the smartest one—it's the one that solves your problem at the lowest cost +- Persistent instructions are recurring costs—they load on every call +- Skills are conditional costs—they only load when invoked +- Attachments are per-call costs—you control exactly what's included +- The engineering target: keep always-on global instructions under 1000 tokens +- Scoped instructions should be discoverable: if a rule only applies to `/api`, put the instruction file in `/api/.github/` diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md index e87130e045..cfe7d9d999 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md @@ -1,64 +1,50 @@ -# Challenge 03 - Session Configuration (Tools + Cache) +# Challenge 03 - Model Selection & Output Constraints [< Previous Challenge](./Challenge-02.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-04.md) ## Introduction -Every MCP tool you enable adds token overhead to every agent step. Each tool's name, description, and parameter schema are advertised to the model on every request—even if the tool is never invoked. A session with many unused tools burns credits before you've written a line of code. +Not all tasks need the most powerful model. A cheaper model with tight output constraints can often outperform an expensive model that produces verbose responses. In this challenge, you'll learn to match models to task complexity and apply output constraints that reduce token generation without sacrificing quality. -Meanwhile, changing configuration mid-session can trigger cache invalidation, forcing expensive cold restarts where previously cached context must be reprocessed. - -In this challenge, you'll measure the real cost of tool sprawl and observe how session hygiene affects your credit spend. +The key insight: credit cost = (input tokens × input rate) + (output tokens × output rate). While you control input through context engineering, output constraints are your lever for controlling what the model generates. ## Description -This challenge has two parts: measuring MCP tool overhead and observing cache invalidation behavior. - -### Part 1: Measure MCP Tool Overhead - -Use GitHub Copilot to scan/find something in the `microsoft/TypeScript` repository and report back. - -If you don't have MCP servers enabled already, try the GitHub MCP server with all its tools. Complete the task with all tools enabled and record your credit spend. - -Next, identify which MCP tools were actually used. +Complete the same coding task from your baseline using different GitHub Copilot models and configurations. Your goal is to understand the cost-quality tradeoff and discover when cheaper models with constraints beat expensive models without them. -Disable the unused tools, repeat the scan, and measure the credit difference. Each unused tool adds token overhead on every agent step because its schema is included in the system prompt. +### Model Comparison -### Part 2: Observe Cache Invalidation +Experiment with the available models in your GitHub Copilot configuration (GPT-4o, Claude Sonnet, Claude Haiku if available, etc.). Complete your baseline coding task with different models and record the total credits consumed, output quality, iteration count, and response verbosity for each. -Complete the repository scan twice more under different conditions: +### Reasoning Levels -**Clean Session:** Configure your tools once, then complete the entire scan without making any configuration changes. Record total credits. +Explore how different reasoning levels affect credit utilization -**Messy Session:** Start the scan, but mid-way through deliberately make configuration changes—disable a tool, edit your `.github/copilot-instructions.md` file, or switch to a different reasoning effort level. Finish the scan and record total credits. +### Auto Mode -Observe which configuration changes cause measurable credit spikes. These spikes indicate cache invalidation—when GitHub Copilot must reprocess previously cached context. +If GitHub Copilot's Auto mode is available, try it on the same task. Observe which models it selects for different subtasks, when it leverages cache, and how total cost compares to manual model selection. Understand the tradeoffs of automatic routing vs. manual control. ## Success Criteria To complete this challenge successfully, you should be able to: -- Show which MCP tools were enabled at the start using the `/context` command -- Complete the TypeScript repository scan and generate a report with file paths and dependencies -- Identify which tools were actually invoked by examining VS Code Output panel logs -- Demonstrate measurable credit savings from disabling unused tools on the same scan task -- Show comparative credit costs between clean session and messy session approaches -- Explain which configuration changes you observed causing cache invalidation -- Document your findings: tool count before/after, credits before/after, credit difference between clean/messy sessions +- Demonstrate completion of the baseline task using multiple different models +- Show measured credit costs for each model with comparable input conditions +- Verify that output quality met acceptance criteria across model tests +- Demonstrate credit cost reduction from applying output constraints +- Show comparative data proving that a cheaper model with constraints can beat an expensive model without constraints +- Explain when Auto mode provides value vs. manual model selection ## Learning Resources -- [Managing Context in GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/context-management) -- [Model Context Protocol Tools Specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools.md) -- [Anthropic Prompt Caching](https://claude.com/blog/prompt-caching) -- [GitHub Copilot Usage-Based Billing](https://docs.github.com/en/copilot/concepts/billing/usage-based-billing-for-organizations-and-enterprises) +- [GitHub Copilot Model Selection Guide](https://docs.github.com/en/copilot) +- [Prompt Engineering: Output Formatting Techniques](https://www.promptingguide.ai/) +- [Understanding Model Pricing and Token Rates](https://docs.github.com/en/copilot/about-github-copilot) ## Tips -- Use `/context` to see which tools are enabled and how much of your token budget they consume -- The VS Code Output panel (View → Output → "GitHub Copilot") shows actual tool invocations -- Each MCP tool's schema (name, description, parameters) is sent to the model on every request -- System prompt changes (like editing instruction files or toggling tools) can invalidate cached context -- Use `/usage` to see your credit breakdown after each task -- The GitHub MCP server typically includes tools like: search_code, get_file_contents, create_issue, search_users, list_pull_requests -- For this scanning task, you likely only need search_code and get_file_contents +- Input tokens are cheaper than output tokens for most models +- Verbose explanations cost credits—request code-only output when you don't need narration +- Haiku-class models can be significantly cheaper than Sonnet/GPT-4 class models +- Auto mode's discount comes from cache-aware routing, but only when task boundaries align with cache boundaries +- The best model isn't always the smartest one—it's the one that solves your problem at the lowest cost diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md index 51f6e6fc6c..ec2efefc17 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md @@ -1,53 +1,64 @@ -# Challenge 04 - Context Window Management +# Challenge 04 - Session Configuration (Tools + Cache) [< Previous Challenge](./Challenge-03.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-05.md) ## Introduction -Context windows grow with every interaction. As your session accumulates messages, attachments, and generated code, the context window fills. When utilization gets too high, quality degrades—responses become less accurate, the model "forgets" earlier decisions, and credits burn faster as you pay to transmit bloated context. +Every MCP tool you enable adds token overhead to every agent step. Each tool's name, description, and parameter schema are advertised to the model on every request—even if the tool is never invoked. A session with many unused tools burns credits before you've written a line of code. -In this challenge, you'll learn when and how to use `/compact` (the steering wheel) vs. `/clear` (the reset button). The biggest avoidable cost isn't running `/compact` too often—it's running it too late, after context rot has already degraded quality and forced expensive recovery loops. +Meanwhile, changing configuration mid-session can trigger cache invalidation, forcing expensive cold restarts where previously cached context must be reprocessed. + +In this challenge, you'll measure the real cost of tool sprawl and observe how session hygiene affects your credit spend. ## Description -Complete a multi-turn coding task designed to intentionally grow your context window. You'll compare two approaches: proactive compaction vs. reactive recovery. +This challenge has two parts: measuring MCP tool overhead and observing cache invalidation behavior. + +### Part 1: Measure MCP Tool Overhead + +Use GitHub Copilot to scan/find something in the `microsoft/TypeScript` repository and report back. -### Context Rot Observation +If you don't have MCP servers enabled already, try the GitHub MCP server with all its tools. Complete the task with all tools enabled and record your credit spend. -Start a coding task that involves multiple related features or refactors. Intentionally let the context window grow by adding numerous file attachments, requesting verbose explanations, and allowing the conversation to accumulate without intervention. +Next, identify which MCP tools were actually used. -Monitor context window utilization (visible in VS Code status bar or Output panel) and observe what happens as it fills. Look for quality degradation signals like inconsistencies, forgotten requirements, or repeated questions. Record credits consumed and note any incorrect outputs or rework needed. +Disable the unused tools, repeat the scan, and measure the credit difference. Each unused tool adds token overhead on every agent step because its schema is included in the system prompt. -### Proactive Compaction +### Part 2: Observe Cache Invalidation -Restart the same multi-turn task using proactive `/compact` at natural breakpoints (after completing a feature, before switching topics). Keep the context window lean throughout and monitor how compaction summarizes previous work while preserving state. Compare credits consumed and output quality vs. the unmanaged approach. +Complete the repository scan twice more under different conditions: -### Emergency Reset +**Clean Session:** Configure your tools once, then complete the entire scan without making any configuration changes. Record total credits. -Demonstrate when `/clear` is appropriate by starting a task where you realize mid-way that your approach is fundamentally wrong. Use `/clear` to wipe context and start fresh with a corrected approach. Understand the cold cache penalty from `/clear` vs. preserved cache with `/compact`. +**Messy Session:** Start the scan, but mid-way through deliberately make configuration changes—disable a tool, edit your `.github/copilot-instructions.md` file, or switch to a different reasoning effort level. Finish the scan and record total credits. +Observe which configuration changes cause measurable credit spikes. These spikes indicate cache invalidation—when GitHub Copilot must reprocess previously cached context. ## Success Criteria To complete this challenge successfully, you should be able to: -- Demonstrate observable quality degradation when context window grows too large -- Show credit cost comparison between unmanaged context growth and proactive compaction approaches -- Verify that proactive `/compact` maintained output quality throughout the multi-turn task -- Demonstrate appropriate use of `/clear` when the context becomes fundamentally misaligned -- Explain the difference in cache impact between `/compact` (preserves cache) and `/clear` (cold restart) +- Show which MCP tools were enabled at the start using the `/context` command +- Complete the TypeScript repository scan and generate a report with file paths and dependencies +- Identify which tools were actually invoked by examining VS Code Output panel logs +- Demonstrate measurable credit savings from disabling unused tools on the same scan task +- Show comparative credit costs between clean session and messy session approaches +- Explain which configuration changes you observed causing cache invalidation +- Document your findings: tool count before/after, credits before/after, credit difference between clean/messy sessions ## Learning Resources -- [Understanding Context Windows and Token Limits](https://www.anthropic.com/index/prompting-long-context) -- [GitHub Copilot Chat Commands Documentation](https://docs.github.com/en/copilot/using-github-copilot/using-github-copilot-chat) -- [Managing Long Conversations with AI Assistants](https://www.promptingguide.ai/) +- [Managing Context in GitHub Copilot CLI](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/context-management) +- [Model Context Protocol Tools Specification](https://modelcontextprotocol.io/specification/2025-06-18/server/tools.md) +- [Anthropic Prompt Caching](https://claude.com/blog/prompt-caching) +- [GitHub Copilot Usage-Based Billing](https://docs.github.com/en/copilot/concepts/billing/usage-based-billing-for-organizations-and-enterprises) ## Tips -- Context rot starts when the window gets too full—don't wait until the last moment -- `/compact` is the steering wheel (summarize, preserve state)—use it proactively -- `/clear` is the reset button (wipe everything)—use it when direction changes -- Natural breakpoints: feature complete, tests passing, architecture decision made -- The cost isn't running `/compact`—it's NOT running `/compact` until quality has already degraded -- Compact before you feel the pain, not after +- Use `/context` to see which tools are enabled and how much of your token budget they consume +- The VS Code Output panel (View → Output → "GitHub Copilot") shows actual tool invocations +- Each MCP tool's schema (name, description, parameters) is sent to the model on every request +- System prompt changes (like editing instruction files or toggling tools) can invalidate cached context +- Use `/usage` to see your credit breakdown after each task +- The GitHub MCP server typically includes tools like: search_code, get_file_contents, create_issue, search_users, list_pull_requests +- For this scanning task, you likely only need search_code and get_file_contents diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index 15553106c4..bd4e67d381 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -1,275 +1,53 @@ -# Challenge 05 - Spec-Driven Development with Spec Kit +# Challenge 05 - Context Window Management [< Previous Challenge](./Challenge-04.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-06.md) ## Introduction -In this challenge, you will experience the difference between **ad-hoc prompting** and **spec-driven development** by building the same application twice — first without structure, then using **GitHub Spec Kit**. +Context windows grow with every interaction. As your session accumulates messages, attachments, and generated code, the context window fills. When utilization gets too high, quality degrades—responses become less accurate, the model "forgets" earlier decisions, and credits burn faster as you pay to transmit bloated context. -Spec Kit is one of several ways to implement spec-driven development with GitHub Copilot. The core principle applies regardless of tooling: **structured context produces better results than conversational prompts**. - -With Spec Kit, you will: - -- Define a **constitution (rules)** -- Create a **spec (what to build)** -- Generate a **plan (how to build)** -- Break it into **tasks** -- Execute implementation - -**Goal:** Experience firsthand how structured specs reduce token usage and improve output quality compared to ad-hoc prompting. - -> **Key Concept:** Spec becomes your context. Not the chat. +In this challenge, you'll learn when and how to use `/compact` (the steering wheel) vs. `/clear` (the reset button). The biggest avoidable cost isn't running `/compact` too often—it's running it too late, after context rot has already degraded quality and forced expensive recovery loops. ## Description -In this challenge, you will build **the same application twice**: - -1. **Part 1:** Build with ad-hoc prompting (no structure) -2. **Part 2:** Build with Spec Kit workflow - -Then compare the results. - -### The Application - -You will build: - -> **A simple notes application** - -Requirements: -1. Create, read, update, and delete notes (CRUD) -2. Each note must have a title (required) and content - -That's it — keep it simple! - ---- - -## Part 1 — Build with Ad-Hoc Prompting - -First, build the application using traditional conversational prompting with Copilot. - -### Step 1 — Create a New Project Folder - -```bash -mkdir notes-app-adhoc -cd notes-app-adhoc -code . -``` - -### Step 2 — Build the Application - -Your goal: Create a working notes application that meets the 2 requirements above. - -**Rules:** -- Use only Copilot Chat with ad-hoc prompts -- No pre-written specs or documentation -- Just start prompting and see what happens - -**Try to complete the application on your own!** - -### Step 3 — Track Your Experience - -As you work, note: -- How many prompts did you need? -- How many times did you repeat the same information? -- Did Copilot "forget" what you asked earlier? -- Was the generated code consistent in style? -- How did it feel? - -### Step 4 — Save Your Results - -Keep this project. You'll compare it later. - ---- - -## Part 2 — Build with Spec Kit - -Now build the **same application** using the Spec Kit workflow. - -### Step 1 — Initialize a New Spec Kit Project - -```bash -specify init notes-app-speckit --integration copilot -cd notes-app-speckit -code . -``` - -### Step 2 — Verify Spec Kit is Ready - -In the project folder, you should see: -- `.specify/` -- `.github/prompts/` -- Markdown files - -In Copilot Chat, type `/` — you should see: -- `/speckit.constitution` -- `/speckit.specify` -- `/speckit.plan` -- `/speckit.tasks` -- `/speckit.implement` - -### Step 3 — Define Constitution - -In Copilot Chat, run: +Complete a multi-turn coding task designed to intentionally grow your context window. You'll compare two approaches: proactive compaction vs. reactive recovery. -``` -/speckit.constitution -``` +### Context Rot Observation -Then describe your rules. Example: +Start a coding task that involves multiple related features or refactors. Intentionally let the context window grow by adding numerous file attachments, requesting verbose explanations, and allowing the conversation to accumulate without intervention. -``` -Simple local application. Clean code with clear separation of concerns. -``` +Monitor context window utilization (visible in VS Code status bar or Output panel) and observe what happens as it fills. Look for quality degradation signals like inconsistencies, forgotten requirements, or repeated questions. Record credits consumed and note any incorrect outputs or rework needed. -This creates the `constitution.md` file containing your system rules. +### Proactive Compaction -### Step 4 — Create Spec +Restart the same multi-turn task using proactive `/compact` at natural breakpoints (after completing a feature, before switching topics). Keep the context window lean throughout and monitor how compaction summarizes previous work while preserving state. Compare credits consumed and output quality vs. the unmanaged approach. -Run: +### Emergency Reset -``` -/speckit.specify -``` +Demonstrate when `/clear` is appropriate by starting a task where you realize mid-way that your approach is fundamentally wrong. Use `/clear` to wipe context and start fresh with a corrected approach. Understand the cold cache penalty from `/clear` vs. preserved cache with `/compact`. -Describe the same requirements as Part 1: - -``` -A notes application with CRUD operations. -Each note has a title (required) and content. -``` - -This creates a `spec.md` file with: -- Requirements -- Acceptance criteria -- User stories - -### Step 5 — (Optional) Clarify - -Run: - -``` -/speckit.clarify -``` - -Spec Kit will ask clarifying questions to improve your spec. This: -- Reduces ambiguity -- Reduces rework later - -### Step 6 — Generate Plan - -Run: - -``` -/speckit.plan -``` - -This generates: -- Architecture decisions -- Technology stack -- Project structure - -### Step 7 — Generate Tasks - -Run: - -``` -/speckit.tasks -``` - -This creates: -- List of small, actionable tasks -- Execution order - -### Step 8 — Implement - -Run: - -``` -/speckit.implement -``` - -Now Copilot will: -- Execute tasks sequentially -- Generate code incrementally - ---- - -## Part 3 — Compare Results - -Now compare both implementations. - -### Questions to Answer - -| Aspect | Ad-Hoc Approach | Spec Kit Approach | -|--------|-----------------|-------------------| -| Total prompts needed | ? | ? | -| Times you repeated context | ? | ? | -| Code consistency | ? | ? | -| Time to complete | ? | ? | -| Quality of output | ? | ? | - -### What to Look For - -- **Context retention:** Did Copilot remember requirements? -- **Consistency:** Did the code follow the same patterns throughout? -- **Completeness:** Were all requirements addressed? -- **Token efficiency:** How much did you have to type? - -## Rules - -- Complete Part 1 before starting Part 2 -- Do NOT skip steps in the Spec Kit workflow -- Review each output before continuing -- Make minimal edits — avoid rewriting everything -- Document your observations for comparison ## Success Criteria To complete this challenge successfully, you should be able to: -- Build the task management API using ad-hoc prompting -- Build the same API using Spec Kit workflow -- Create a constitution that defines project rules and standards -- Generate a spec from your requirements description -- Produce a structured plan from the spec -- Break the plan into executable tasks -- Compare both approaches and articulate the differences -- Demonstrate reduced token usage with spec-driven development -- Show improved output consistency and predictability +- Demonstrate observable quality degradation when context window grows too large +- Show credit cost comparison between unmanaged context growth and proactive compaction approaches +- Verify that proactive `/compact` maintained output quality throughout the multi-turn task +- Demonstrate appropriate use of `/clear` when the context becomes fundamentally misaligned +- Explain the difference in cache impact between `/compact` (preserves cache) and `/clear` (cold restart) ## Learning Resources -- [GitHub Spec Kit Repository](https://github.com/github/spec-kit) -- [Spec Kit Installation Guide](https://github.com/github/spec-kit/blob/main/docs/installation.md) -- [Spec-Driven Development with GitHub Spec Kit](https://medium.com/@vamshi.rapolu/spec-driven-development-with-github-spec-kit-copilot-in-vs-code-new-existing-projects-2531d10bd61d) -- [Spec Kit Commands Reference](https://easyguides.net/guides/spec-kit/commands) -- [Plan and Tasks Commands Tutorial](https://codestandup.com/posts/2025/github-spec-kit-tutorial-plan-tasks-commands/) +- [Understanding Context Windows and Token Limits](https://www.anthropic.com/index/prompting-long-context) +- [GitHub Copilot Chat Commands Documentation](https://docs.github.com/en/copilot/using-github-copilot/using-github-copilot-chat) +- [Managing Long Conversations with AI Assistants](https://www.promptingguide.ai/) ## Tips -- Part 1 intentionally feels inefficient — that's the point! -- Spec becomes your persistent context — no need to repeat requirements -- The constitution acts as guardrails that apply to all generated code -- Use `/speckit.clarify` when requirements feel ambiguous -- Each step builds on the previous — the workflow is designed to be sequential -- Review generated specs and plans before proceeding to catch issues early -- Small, focused specs produce better results than large, vague ones - -## Reflection Questions - -After completing this challenge, answer: - -1. How did Part 1 (ad-hoc) feel compared to Part 2 (Spec Kit)? -2. How many times did you repeat context in each approach? -3. Did the outputs become more predictable with Spec Kit? -4. How would spec-driven development impact token usage and costs in real projects? -5. What other tools or methods could achieve similar spec-driven benefits? - -## Advanced Challenges - -Too comfortable? Try these: - -- Apply Spec Kit to an existing project instead of a new one -- Create multiple specs for different features and observe how they interact -- Measure credit consumption between both approaches for the same feature -- Customize the constitution for different project types (frontend, backend, full-stack) +- Context rot starts when the window gets too full—don't wait until the last moment +- `/compact` is the steering wheel (summarize, preserve state)—use it proactively +- `/clear` is the reset button (wipe everything)—use it when direction changes +- Natural breakpoints: feature complete, tests passing, architecture decision made +- The cost isn't running `/compact`—it's NOT running `/compact` until quality has already degraded +- Compact before you feel the pain, not after From 5be6e46acba1d588177e3fd2d5c1c48044e48a1c Mon Sep 17 00:00:00 2001 From: anefedova <anefedova@microsoft.com> Date: Thu, 25 Jun 2026 22:01:42 -0400 Subject: [PATCH 22/48] Build Challenge 03: Model Selection & Output Constraints Rewrite Challenge 03 into a runnable two-task comparison (easy vs hard, cheap vs expensive model) measuring outcome + tokens, with no-retry rule. - Student/Challenge-03.md: Part 1 (easy: version sort, cheap wins on tokens), Part 2 (hard: letter count, cheap model confidently wrong), Part 3 compare, optional output-constraints section. - Student/Resources/Challenge-03-ModelSelection: README, prompts, measurements-template, output-constraints cheat sheet. - Coach/Solution-03.md: mechanic, measured answer key (n=4), no-retry guidance, blockers, hints. - Coach/Solutions/Challenge-03-ModelSelection-Solutions: harness.py + results.md (gpt-4.1-nano vs gpt-5, validated via GitHub Models API). - Coach/README.md: list Challenge 03 resources. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Coach/README.md | 1 + .../Coach/Solution-03.md | 115 ++++++++++----- .../README.md | 30 ++++ .../TODO.md | 49 +++++++ .../harness.py | 127 +++++++++++++++++ .../results.md | 36 +++++ .../Student/Challenge-03.md | 133 +++++++++++++++--- .../Challenge-03-ModelSelection/README.md | 28 ++++ .../measurements-template.md | 58 ++++++++ .../output-constraints.md | 28 ++++ .../Challenge-03-ModelSelection/prompts.md | 44 ++++++ 11 files changed, 596 insertions(+), 53 deletions(-) create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py create mode 100644 xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/README.md b/xxx-GitHubCopilotCostOptimization/Coach/README.md index 0a0cbe3617..6483a26ad5 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/README.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/README.md @@ -42,6 +42,7 @@ The Student/Resources folder should contain: - Multiple MCP tools enabled (some unnecessary) for Challenge 04 - Sample code with opportunities for spec-first vs. trial-and-error comparison - **Baseline coding task** (baseline-task.md) for Challenge 00 +- **Model selection prompts + measurement template** (`Challenge-03-ModelSelection/`) for Challenge 03 - **Token Golf task specification** for Challenge 06 with acceptance criteria Always refer students to the [What The Hack website](https://aka.ms/wth) for the student guide: [https://aka.ms/wth](https://aka.ms/wth) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md index 7d690a4d95..c163cf1252 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md @@ -1,49 +1,100 @@ -# Challenge 03 - Model Selection & Output Constraints - Coach's Guide +# Challenge 03 - Model Selection & Output Constraints - Coach's Guide [< Previous Solution](./Solution-02.md) - **[Home](./README.md)** - [Next Solution >](./Solution-04.md) ## Notes & Guidance -This challenge demonstrates that credit cost depends on both model selection and output volume. A cheaper model with tight constraints often beats an expensive model with verbose output. +This challenge teaches one durable idea: **total cost = token rate × tokens × attempts**, so +*cheap-per-token is not cheap-per-task.* Students prove it by running the same prompt on a +cheap and an expensive model across an **easy** task and a **hard** task, measuring outcome +and tokens. The magic is the contrast: opposite winners on the two tasks. -### Key Concepts to Explain +### The core mechanic -**Model Pricing Hierarchy (Approximate):** -- GPT-4o class: ~1x baseline cost -- Claude Sonnet: ~1x baseline cost -- Claude Haiku: ~0.1x baseline cost (10x cheaper) +| | Easy task (version sort) | Hard task (letter count) | +|---|---|---| +| Cheap model | ✅ correct, **fewer tokens** | ❌ confidently wrong, few tokens (a trap) | +| Strong model | ✅ correct, more tokens | ✅ correct, more tokens | +| **Lesson** | Use the cheap model → save credits | Cheap wrong answer is the costliest option → pay for capability | -**Output constraints as cost controls:** -- "Output code only" eliminates explanation tokens -- JSON schema constrains response format -- Word limits ("explain in <50 words") cap verbosity -- Structured output prevents rambling +### Reference answer key (measured) -### Key Data Points to Share +Measured via the GitHub Models inference API, **n=4 per cell** (see +`Solutions/Challenge-03-ModelSelection-Solutions/`). Exact numbers will vary by model/version; +the **pattern** is what matters. -**Real-world comparison:** -- Regular Agent Mode (Sonnet): ~65 credits for a moderate task -- Custom Agent (Haiku) with "code only" constraint: ~7.6 credits for same task -- Savings: 88% reduction by choosing cheaper model + output constraints +| Model | Easy: pass rate | Easy: avg tokens | Hard: pass rate | Hard: avg tokens | +|---|---|---|---|---| +| `gpt-4.1-nano` (cheap) | **4/4 (100%)** | ~93 | **0/4 (0%)** — always "4" | ~31 | +| `gpt-5` (strong) | **4/4 (100%)** | ~325 | **4/4 (100%)** | ~391 | -**When to use each model:** -- Haiku: Boilerplate, refactoring, well-defined tasks -- Sonnet/GPT-4: Complex logic, architecture decisions, debugging novel issues -- Auto mode: Let GitHub Copilot route based on complexity (10% discount for cache-aware routing) +Takeaways to draw out: +- Easy task: identical correct answer, but the cheap model used **~3.5× fewer tokens.** +- Hard task: the cheap model was wrong **every** time and *cheaper* — the low cost is + worthless because the answer is wrong. The strong model cost ~13× the cheap model's tokens + and was the only one correct. -### Expected Time +### Why these specific tasks -60 minutes: -- 20 minutes: Complete baseline task with 3+ different models -- 20 minutes: Apply output constraints to one model -- 20 minutes: Measure and document findings +- **Version sort (easy):** real, practical, and both tiers get it right — so the only + differentiator is token cost. Clean "cheap wins" demonstration. +- **Letter counting (hard):** exploits a structural weakness (tokenization) that small models + reliably fail, and the answer is **human-verifiable in seconds** — students can *see* the + cheap model is wrong without trusting us. +- **Rejected:** the coin-change "greedy trap." We tested it — modern small models pass it, so + it does NOT discriminate. Don't use reasoning puzzles that cheap models have caught up on. -### Success Criteria Validation +### The "no retry" rule (important) -Students should show credit cost comparison table across models and demonstrate measurable savings from output constraints. +Tell students explicitly: when the cheap model fails Part 2, **do not coach or retry it.** The +point is the first-shot outcome. In real workflows the hidden cost is the human time + extra +tokens spent discovering the answer is wrong and redoing it. Retrying hides that lesson. -### Hints to Share +## How students run it -- The fastest model isn't always the cheapest—total credits = input rate + output rate -- If your prompt is 1000 tokens and response is 500 tokens, output constraints save more than model switching -- Auto mode's 10% discount comes from cache-aware routing, but only when natural task boundaries align +No codebase. Students use the **VS Code Copilot Chat model picker** to switch between a +cheap-tier and strong-tier model, paste the two prompts from +`Student/Resources/Challenge-03-ModelSelection/prompts.md`, and read tokens from the Output +panel / `/usage`. They fill in `measurements-template.md`. + +> Orgs expose different models. Coach students to pick *any* cheap-tier vs strong-tier pair +> their picker offers — the pattern holds. If your org only exposes one tier, use the coach +> answer key above as the demonstration. + +## Expected Time + +~45 minutes: +- 15 min: Part 1 (easy) on both models +- 15 min: Part 2 (hard) on both models +- 10 min: Part 3 compare + discussion +- 5 min: optional output-constraint run + +## Success Criteria Validation + +Students should produce a completed Part 3 table showing **opposite winners**: cheap model +wins the easy task on tokens; strong model is the only correct option on the hard task. Bonus: +a measurable token drop on the strong model when an output constraint is added to Part 1. + +## Common Blockers + +- **Student retries the cheap model until it's right.** Stop them — that defeats the lesson. +- **Org exposes only one model tier.** Fall back to the answer key, or use the coach harness + to demo live. +- **Token counts not visible.** Ensure the GitHub Copilot extension is current and the Output + panel "GitHub Copilot Chat" channel is selected (covered in Challenge 00). +- **Cheap model happens to pass the hard task once.** It's stochastic; have them run it 2–3×. + It fails the large majority of the time. + +## Hints to Share + +- "Cheap" is about *total* cost, not per-token price. A wrong answer you have to redo is the + most expensive outcome. +- Match the model to the task: cheap for well-defined/low-ambiguity work, strong for anything + needing real reasoning. +- Output constraints cut cost on any model — but they don't make a wrong model right. + +## Reference Data & Reproduction + +See `Solutions/Challenge-03-ModelSelection-Solutions/`: +- `harness.py` — measurement harness (counts pass/fail + tokens, with rate-limit backoff) +- `results.md` — the measured tables above diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md new file mode 100644 index 0000000000..8a4298c940 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md @@ -0,0 +1,30 @@ +# Challenge 03 — Coach Solution Assets + +Reference data and tooling for the coach. **Not** distributed to students — students use the +VS Code Copilot Chat model picker + Output panel. + +## Contents + +| File | Purpose | +|---|---| +| `harness.py` | Measurement harness: runs N trials of each (model, task), counts pass/fail, averages tokens, with rate-limit backoff | +| `results.md` | The measured answer-key tables referenced in `Solution-03.md` | + +## Running the harness + +The harness calls the **GitHub Models inference API** and authenticates with your +`gh auth token`. + +```bash +# default: gpt-4.1-nano vs gpt-5, both tasks, n=4 +python harness.py --models "openai/gpt-4.1-nano" "openai/gpt-5" --tasks sort letter -n 4 --sleep 2 +``` + +Output is a summary table of pass rate + average tokens per (model, task), and a +`results.json` dump. + +### Notes +- The free GitHub Models tier is rate-limited; the harness backs off on HTTP 429. For large N, + expect it to run slowly. n=4 is sufficient to demonstrate the pattern. +- Strong models (e.g. `gpt-5`) throttle the most. Increase `--sleep` if you see many retries. +- `--tasks` accepts `sort` (easy) and `letter` (hard). diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md new file mode 100644 index 0000000000..e9fdfcc529 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md @@ -0,0 +1,49 @@ +# Challenge 03 — Deferred Enhancements (TODO) + +Coach/author notes. The challenge as committed is **complete and runnable**, but a review +(walking it against Challenges 01/02 and running it live) flagged that the *concept* is strong +while the *activity* is light (~10 min: 4 prompts + a table) compared to C01/C02 (30–60 min of +hands-on building). The items below would bring it to C01-level depth without losing the crisp +"cheap-per-token ≠ cheap-per-task" framing. Handle in a follow-up. + +## A. Add activity depth (fills the 45-min slot) +- [ ] "**Classify your own task**" exercise: student writes 2 real tasks from their own work, + predicts easy→cheap vs hard→strong, runs each on both model tiers, and checks the + prediction. Makes the lesson personal and transferable. +- [ ] Add an **Advanced Challenges** section (C01 has one; C03 currently doesn't): + - Try a **mid-tier / reasoning-tier** model on the hard task — where's the price/capability knee? + - Build a **two-model workflow**: cheap model drafts, strong model reviews — measure total cost. + - Try **Auto mode** (if the org exposes it) and compare routing + cost to manual selection. + +## B. Pre-empt the "gotcha" objection +- [ ] Add ~1 paragraph: the letter-count task tests the model's **direct reasoning**, not its + ability to emit code. A sharp student will say "I'd just have it write code to count." + Connect it to agentic coding: the model constantly reasons *within* tasks (choosing logic, + comparing values, judging correctness) — and that is exactly where a weak model is + confidently wrong. Model selection governs reasoning quality, not just code emission. + +## C. Token-count variance note +- [ ] Add a note in the student doc: token counts vary run-to-run (strong models especially — + reasoning tokens). Observed gpt-5 on the easy task: 229 / 325 / 357 tokens across runs. + Tell students to **focus on the pattern / ratio, not the absolute number**, and to run a + task 2–3× if a result looks anomalous. + +## D. Scope decision (was in the ORIGINAL Challenge-03, dropped in the rewrite) +- [ ] Decide whether to re-add, likely as **optional/Advanced**: + - **Reasoning levels** — compare credit use across reasoning-effort settings. + - **Auto mode** — when automatic routing beats manual model choice (original success criterion + was "Explain when Auto mode provides value vs. manual selection"). +- Options discussed: (1) re-add both as Advanced, (2) leave out for focus, (3) add Auto mode only. + Pending owner sign-off. + +## Validated data (do not lose — basis for the answer key) +Measured via GitHub Models API (`harness.py`), single-shot, no retries: + +| Model | Easy (version sort) | Hard (letter count) | +|---|---|---| +| gpt-4.1-nano (cheap) | ✅ 4/4 pass, ~93 tok | ❌ 0/4 pass, ~31 tok (always "4") | +| gpt-5 (strong) | ✅ 4/4 pass, ~229–357 tok | ✅ 4/4 pass, ~295–391 tok | + +Output constraint (gpt-5, easy task): 229 → 169 tok = **−26%**, identical answer. +Rejected: ministral-3b (too weak — fails the easy task); coin-change greedy trap (modern small +models pass it — no longer discriminates). diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py new file mode 100644 index 0000000000..54f921622c --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python3 +""" +Statistical model-comparison harness for WTH Challenge 03. + +Runs N trials of each (model, task) pair, counts pass/fail, averages tokens. +Handles 429 rate limits with exponential backoff (a rate-limited call is +retried, NOT counted as a task failure). +""" +import argparse +import json +import re +import subprocess +import sys +import time +import urllib.error +import urllib.request + +ENDPOINT = "https://models.github.ai/inference/chat/completions" + +# ---- Tasks ----------------------------------------------------------------- +SORT_PROMPT = ("Sort these software version numbers from oldest to newest and " + "list them in order separated by commas: 1.9.0, 1.10.0, 1.2.0, " + "1.11.0, 1.9.5") +LETTER_PROMPT = ("How many times does the letter l appear in the phrase " + "'parallel lullaby'? Answer with only the number.") + + +def check_sort(ans: str) -> bool: + versions = re.findall(r"\d+\.\d+\.\d+", ans) + return versions == ["1.2.0", "1.9.0", "1.9.5", "1.10.0", "1.11.0"] + + +def check_letter(ans: str) -> bool: + m = re.search(r"\d+", ans) + return m is not None and m.group() == "6" + + +TASKS = { + "sort": {"prompt": SORT_PROMPT, "check": check_sort}, + "letter": {"prompt": LETTER_PROMPT, "check": check_letter}, +} + + +def get_token() -> str: + return subprocess.check_output(["gh", "auth", "token"], text=True).strip() + + +def call(token: str, model: str, prompt: str, max_retries: int = 6): + """Returns (answer, total_tokens) or ('ERROR:...', 0). Retries on 429.""" + body = json.dumps( + {"model": model, "messages": [{"role": "user", "content": prompt}]} + ).encode() + for attempt in range(max_retries): + req = urllib.request.Request( + ENDPOINT, data=body, + headers={"Authorization": f"Bearer {token}", + "Content-Type": "application/json"}, + method="POST", + ) + try: + with urllib.request.urlopen(req) as resp: + d = json.load(resp) + return (d["choices"][0]["message"]["content"].strip(), + d["usage"]["total_tokens"]) + except urllib.error.HTTPError as e: + if e.code == 429: + wait = min(60, 2 ** attempt * 5) + time.sleep(wait) + continue + return (f"ERROR:{e.code}", 0) + except Exception as e: # noqa: BLE001 + return (f"ERROR:{e}", 0) + return ("ERROR:429-exhausted", 0) + + +def run(token: str, model: str, task_key: str, n: int, sleep: float): + task = TASKS[task_key] + passes, toks, errors = 0, [], 0 + for i in range(n): + ans, t = call(token, model, task["prompt"]) + if ans.startswith("ERROR:"): + errors += 1 + else: + if task["check"](ans): + passes += 1 + toks.append(t) + done = i + 1 + if done % 10 == 0 or done == n: + print(f" {model} / {task_key}: {done}/{n} " + f"(pass={passes} err={errors})", flush=True) + time.sleep(sleep) + avg = sum(toks) / len(toks) if toks else 0 + valid = n - errors + rate = (passes / valid * 100) if valid else 0 + return {"model": model, "task": task_key, "n": n, "valid": valid, + "passes": passes, "errors": errors, "pass_rate": rate, + "avg_tokens": avg} + + +def main() -> None: + ap = argparse.ArgumentParser() + ap.add_argument("--models", nargs="+", required=True) + ap.add_argument("--tasks", nargs="+", default=["sort", "letter"]) + ap.add_argument("-n", type=int, default=50) + ap.add_argument("--sleep", type=float, default=1.0) + args = ap.parse_args() + + token = get_token() + results = [] + for model in args.models: + for task_key in args.tasks: + print(f" -> {model} / {task_key} (n={args.n})", flush=True) + results.append(run(token, model, task_key, args.n, args.sleep)) + + print("\n" + "=" * 84) + print(f"{'MODEL':<34}{'TASK':<8}{'PASS':>8}{'/N':>6}{'RATE':>8}{'AVG TOK':>10}{'ERR':>6}") + print("-" * 84) + for r in results: + print(f"{r['model']:<34}{r['task']:<8}{r['passes']:>8}{r['valid']:>6}" + f"{r['pass_rate']:>7.0f}%{r['avg_tokens']:>10.0f}{r['errors']:>6}") + print("=" * 84) + with open("results.json", "w") as f: + json.dump(results, f, indent=2) + + +if __name__ == "__main__": + main() diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md new file mode 100644 index 0000000000..4bba38dbd8 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md @@ -0,0 +1,36 @@ +# Challenge 03 — Measured Results (Answer Key) + +Source: GitHub Models inference API. Method: `harness.py`, **n=4 trials per (model, task)**, +single-shot (no retries). Exact token counts vary by model version; the **pattern is stable.** + +## Summary + +| Model | Task | Pass rate | Avg total tokens | +|---|---|---|---| +| `openai/gpt-4.1-nano` (cheap) | sort (easy) | **4/4 — 100%** | 93 | +| `openai/gpt-4.1-nano` (cheap) | letter (hard) | **0/4 — 0%** (always "4") | 31 | +| `openai/gpt-5` (strong) | sort (easy) | **4/4 — 100%** | 325 | +| `openai/gpt-5` (strong) | letter (hard) | **4/4 — 100%** | 391 | + +## Interpretation + +- **Easy task (version sort):** both models 100% correct. The cheap model produced the + identical answer using **~3.5× fewer tokens** (93 vs 325). Paying for the strong model here + buys nothing → **use the cheap model.** +- **Hard task (letter count):** the cheap model was **wrong every single time** (always "4") + and was *cheaper* in tokens — the low cost is a trap because the output is useless. The + strong model was the only correct option, at ~13× the cheap model's token cost → + **pay for capability.** + +## Models we evaluated and rejected as the "cheap" pick + +| Model | Why rejected | +|---|---| +| `mistral-ai/ministral-3b` | Too weak — failed the **easy** task (2/8), breaking the "cheap wins Part 1" story | +| coin-change "greedy trap" task | Modern small models pass it — no longer discriminates; replaced with letter counting | + +## Reproduce + +```bash +python harness.py --models "openai/gpt-4.1-nano" "openai/gpt-5" --tasks sort letter -n 4 --sleep 2 +``` diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md index cfe7d9d999..9e3c1c1802 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md @@ -4,47 +4,138 @@ ## Introduction -Not all tasks need the most powerful model. A cheaper model with tight output constraints can often outperform an expensive model that produces verbose responses. In this challenge, you'll learn to match models to task complexity and apply output constraints that reduce token generation without sacrificing quality. +Not every task needs the most powerful model. Under usage-based billing, cost is **not** just the model's per-token price. It is: -The key insight: credit cost = (input tokens × input rate) + (output tokens × output rate). While you control input through context engineering, output constraints are your lever for controlling what the model generates. +> **Total cost = token rate × tokens × attempts** + +That last term — *attempts* — is the one people forget. A cheap model that answers a simple task correctly in a few tokens is a bargain. But that same cheap model, set loose on a task it cannot actually reason through, will hand you a **confident, wrong answer**. Now you are paying again (and again) to notice it is wrong and redo the work. The "cheap" model just became the expensive one. + +In this challenge you will run the **same prompt against a cheap model and an expensive model — twice.** First on an **easy** task, then on a **hard** task. Every run, you measure two things: **the outcome (did it get it right?)** and **the token cost**. From that data you will build the skill this challenge is really about: deciding *which model to use for which job.* + +> **Key Concept:** Cheap-per-token is not the same as cheap-per-task. ## Description -Complete the same coding task from your baseline using different GitHub Copilot models and configurations. Your goal is to understand the cost-quality tradeoff and discover when cheaper models with constraints beat expensive models without them. +You will run **two tasks**, each against **two models**: + +- A **cheap / lightweight model** — e.g. a "mini", "nano", "Haiku", or "Flash" tier model +- An **expensive / frontier model** — e.g. a GPT-5, Claude Sonnet, or o-series tier model + +> Use whatever cheap-tier and strong-tier models your organization exposes in the GitHub Copilot Chat **model picker**. The exact names don't matter — the *pattern* does. + +For every run, record the **outcome** (correct / incorrect) and the **token usage** from the VS Code Output panel (`View → Output → "GitHub Copilot Chat"`) and/or `/usage`. + +> **Rule — no retries:** When the cheap model gets it wrong, **do not coach it or try again.** Record the failure and move on. The whole point is to see what each model produces *on the first shot* for each kind of task. + +--- + +## Part 1 — An Easy Task (the cheap model should win) + +Give **both** models this exact prompt: + +``` +Sort these software version numbers from oldest to newest and list them in +order separated by commas: 1.9.0, 1.10.0, 1.2.0, 1.11.0, 1.9.5 +``` + +✅ Correct answer: `1.2.0, 1.9.0, 1.9.5, 1.10.0, 1.11.0` + +### Record + +| | Cheap model | Expensive model | +|---|---|---| +| Correct? | ? | ? | +| Total tokens | ? | ? | + +### What to notice + +Both models should get this right. Now compare the **token counts**. The expensive model often produces far more output — restated reasoning, explanations — for the *exact same correct answer*. On an easy task, that extra spend buys you nothing. + +--- -### Model Comparison +## Part 2 — A Hard Task (the cheap model should fail) -Experiment with the available models in your GitHub Copilot configuration (GPT-4o, Claude Sonnet, Claude Haiku if available, etc.). Complete your baseline coding task with different models and record the total credits consumed, output quality, iteration count, and response verbosity for each. +Now give **both** models this exact prompt: -### Reasoning Levels +``` +How many times does the letter l appear in the phrase 'parallel lullaby'? +Answer with only the number. +``` -Explore how different reasoning levels affect credit utilization +✅ Correct answer: `6` (count them yourself: para**ll**e**l** = 3, **l**u**ll**aby = 3) -### Auto Mode +### Record -If GitHub Copilot's Auto mode is available, try it on the same task. Observe which models it selects for different subtasks, when it leverages cache, and how total cost compares to manual model selection. Understand the tradeoffs of automatic routing vs. manual control. +| | Cheap model | Expensive model | +|---|---|---| +| Correct? | ? | ? | +| Total tokens | ? | ? | + +### What to notice + +The cheap model will likely answer **confidently and incorrectly** (a very common answer is `4`). You can verify the right answer yourself in seconds — *that is the point.* The wrong answer is also **cheap in tokens**, which is exactly the trap: low token cost, zero value. + +The expensive model gets it right, and costs **more** tokens to do so. For this kind of task, those extra tokens are not waste — they are the price of a *correct* answer. + +> Do **not** retry the cheap model. A wrong answer is the result. In the real world, the hidden cost of a cheap wrong answer is the time and tokens you burn discovering it is wrong and redoing the work. + +--- + +## Part 3 — Compare Results & Decide + +Combine your measurements into one table: + +| Task | Cheap: correct? | Cheap: tokens | Strong: correct? | Strong: tokens | Which model should you use? | +|------|-----------------|---------------|------------------|----------------|-----------------------------| +| Part 1 (easy) | ? | ? | ? | ? | ? | +| Part 2 (hard) | ? | ? | ? | ? | ? | + +### Questions to Answer + +1. On the **easy** task, which model gave the better *value* (correct answer, fewest tokens)? +2. On the **hard** task, what did the cheap model's wrong answer actually "cost" you — even though it used fewer tokens? +3. If you ran each task **10,000 times a day**, how would your model choice differ between Part 1 and Part 2? +4. How would you decide, *before* running a task, whether it is a "Part 1" (easy → cheap) task or a "Part 2" (hard → strong) task? + +--- + +## Optional — Output Constraints + +Output tokens usually cost more than input tokens. Re-run **Part 1 with the expensive model**, but add an output constraint to the prompt: + +``` +...Answer with only the comma-separated list and nothing else. +``` + +Record the token difference vs. your earlier Part 1 run. Constraining output — "answer only", "code only", "explain in under 50 words", or a JSON schema — is a lever you control on **every** model, cheap or expensive. ## Success Criteria To complete this challenge successfully, you should be able to: -- Demonstrate completion of the baseline task using multiple different models -- Show measured credit costs for each model with comparable input conditions -- Verify that output quality met acceptance criteria across model tests -- Demonstrate credit cost reduction from applying output constraints -- Show comparative data proving that a cheaper model with constraints can beat an expensive model without constraints -- Explain when Auto mode provides value vs. manual model selection +- Run the same prompt against a cheap and an expensive model for both tasks +- Record outcome (correct/incorrect) and token usage for all four runs +- Show that on the easy task the cheap model was correct **and** cheaper +- Show that on the hard task the cheap model was confidently wrong while the expensive model was correct +- Demonstrate a token reduction on the expensive model by adding an output constraint +- Articulate a rule of thumb for deciding which model to use for a given task ## Learning Resources - [GitHub Copilot Model Selection Guide](https://docs.github.com/en/copilot) - [Prompt Engineering: Output Formatting Techniques](https://www.promptingguide.ai/) -- [Understanding Model Pricing and Token Rates](https://docs.github.com/en/copilot/about-github-copilot) +- [GitHub Copilot Usage-Based Billing](https://docs.github.com/en/copilot/concepts/billing/usage-based-billing-for-organizations-and-enterprises) ## Tips -- Input tokens are cheaper than output tokens for most models -- Verbose explanations cost credits—request code-only output when you don't need narration -- Haiku-class models can be significantly cheaper than Sonnet/GPT-4 class models -- Auto mode's discount comes from cache-aware routing, but only when task boundaries align with cache boundaries -- The best model isn't always the smartest one—it's the one that solves your problem at the lowest cost +- Cost = token rate × tokens × **attempts**. A cheap *wrong* answer can be the most expensive option. +- The cheap model is great for well-defined, low-ambiguity work — and it is wasteful to *avoid* it there. +- The expensive model earns its price on tasks that need real reasoning, where a wrong first answer is costly. +- Output constraints reduce cost on *any* model — ask for the answer only when you don't need narration. +- The best model is not the smartest one — it is the one that returns a *correct* answer at the lowest total cost. + +## Reflection Questions + +1. Describe a real task from your own work that is a "Part 1" task. Which model would you use and why? +2. Describe a real "Part 2" task. How would you justify the higher per-token cost to your team? +3. How could you combine cheap and expensive models in a single workflow to minimize total cost (e.g., cheap model drafts, strong model reviews)? diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md new file mode 100644 index 0000000000..62d16eecaf --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md @@ -0,0 +1,28 @@ +# Challenge 03 — Model Selection — Resources + +This folder contains everything you need for Challenge 03. There is **no codebase to run** — +the challenge is about sending two short prompts to two different models and measuring what +comes back. + +## What's here + +| File | Purpose | +|---|---| +| `prompts.md` | The two exact prompts (easy + hard) and their correct answers | +| `measurements-template.md` | Blank tables to record outcome + tokens for each run | +| `output-constraints.md` | Cheat sheet of output constraints to reduce token cost | + +## How to run it (VS Code + GitHub Copilot Chat) + +1. Open GitHub Copilot Chat in VS Code. +2. Use the **model picker** to select a **cheap-tier** model (e.g. a "mini" / "nano" / + "Haiku" / "Flash" model your org exposes). +3. Paste a prompt from `prompts.md` exactly as written. Record the answer and the token + usage from `View → Output → "GitHub Copilot Chat"` (and/or `/usage`). +4. Switch the model picker to an **expensive-tier** model (e.g. GPT-5 / Sonnet / o-series) + and run the **same** prompt. Record again. +5. Repeat for both the easy and the hard prompt. +6. Fill in `measurements-template.md` and answer the Part 3 questions. + +> **Rule:** Do not retry or coach the cheap model when it gets the hard task wrong. A wrong +> first answer is a valid — and important — result. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md new file mode 100644 index 0000000000..8ea07ec938 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md @@ -0,0 +1,58 @@ +# Challenge 03 — Measurement Template + +Fill in the tables as you run each prompt. Get token counts from +`View → Output → "GitHub Copilot Chat"` and/or `/usage`. + +Record the **cheap-tier** and **strong-tier** model names you actually used: + +- Cheap model: `____________________` +- Strong model: `____________________` + +--- + +## Part 1 — Easy task (version sort) + +| | Cheap model | Strong model | +|---|---|---| +| Answer given | | | +| Correct? (Y/N) | | | +| Total tokens | | | + +**Observation:** _Were both correct? Which used fewer tokens for the same answer?_ + +--- + +## Part 2 — Hard task (letter count) + +| | Cheap model | Strong model | +|---|---|---| +| Answer given | | | +| Correct? (Y/N) | | | +| Total tokens | | | + +**Observation:** _Did the cheap model fail? Was its wrong answer "cheap"?_ + +--- + +## Optional — Output constraint (Part 1, strong model) + +| | Strong model (no constraint) | Strong model (answer-only) | +|---|---|---| +| Total tokens | | | +| Token reduction | — | | + +--- + +## Part 3 — Decision table + +| Task | Cheap correct? | Cheap tokens | Strong correct? | Strong tokens | Use which model? | +|------|----------------|--------------|-----------------|---------------|------------------| +| Part 1 (easy) | | | | | | +| Part 2 (hard) | | | | | | + +### Answers + +1. Easy task — better value (correct + fewest tokens)? → +2. Hard task — what did the cheap wrong answer really cost? → +3. At 10,000 runs/day, how does your choice differ for Part 1 vs Part 2? → +4. How do you decide *up front* whether a task is "easy → cheap" or "hard → strong"? → diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md new file mode 100644 index 0000000000..4ce107ac1e --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md @@ -0,0 +1,28 @@ +# Output Constraints — Cheat Sheet + +Output tokens usually cost more than input tokens. Constraining what the model *produces* is +a cost lever you control on **every** model. Use these patterns when you don't need narration. + +| Goal | Add to your prompt | Effect | +|---|---|---| +| Answer only | "Answer with only the number/value, nothing else." | Removes restated reasoning + preamble | +| Code only | "Output only the code. No explanation, no markdown fences." | Cuts the "Here's how it works..." paragraphs | +| Cap verbosity | "Explain in 50 words or fewer." | Hard ceiling on output length | +| Structured output | "Respond as JSON matching: `{ \"result\": number }`" | Prevents rambling; easy to parse | +| No restatement | "Do not repeat the question or summarize the task." | Removes echo of the input | +| Bounded list | "List at most 3 items." | Stops over-generation | + +## Why it matters + +A strong model asked an easy question will often spend most of its tokens *explaining* an +answer you already trust. The constraint keeps the correctness and drops the cost. + +## Try it + +Take any Part 1 run on the strong model and re-run it with `"Answer with only the +comma-separated list and nothing else."` appended. Compare total tokens — the answer is +identical, the cost is lower. + +> Note: constraints reduce **output** tokens. They do not fix a model that is *wrong* +> (see Part 2). For a task the cheap model can't reason through, a constraint just gives you +> a wrong answer faster — model selection, not output shape, is the fix there. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md new file mode 100644 index 0000000000..10962b6a60 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md @@ -0,0 +1,44 @@ +# Challenge 03 — Prompts + +Run each prompt **verbatim**. Do not add context, attachments, or instructions — keeping the +input identical across models is what makes the token comparison fair. + +--- + +## Part 1 — Easy task (version sort) + +``` +Sort these software version numbers from oldest to newest and list them in +order separated by commas: 1.9.0, 1.10.0, 1.2.0, 1.11.0, 1.9.5 +``` + +✅ **Correct answer:** `1.2.0, 1.9.0, 1.9.5, 1.10.0, 1.11.0` + +A wrong answer usually sorts the versions as text (so `1.10.0` and `1.11.0` land before +`1.9.0`). Modern models — cheap or strong — almost always get this right. + +--- + +## Part 2 — Hard task (letter count) + +``` +How many times does the letter l appear in the phrase 'parallel lullaby'? +Answer with only the number. +``` + +✅ **Correct answer:** `6` + +Count it yourself: `para`**`l`**`` `l` ``e`**`l`** → 3, and `` `l` ``u`**`l`**`l`aby → 3. +A cheap model very commonly answers `4` — confidently, and in very few tokens. + +--- + +## Optional — Output constraint variant (Part 1, strong model) + +``` +Sort these software version numbers from oldest to newest: 1.9.0, 1.10.0, 1.2.0, +1.11.0, 1.9.5. Answer with only the comma-separated list and nothing else. +``` + +Same task, but the constraint suppresses the explanation the strong model would otherwise +produce. Compare the token count to your original Part 1 run with the same model. From a71907dfbe39b10962ed05cc3043d9dd5bbd5897 Mon Sep 17 00:00:00 2001 From: ana-codes-1 <ana-codes-1@users.noreply.github.com> Date: Mon, 29 Jun 2026 12:00:37 -0400 Subject: [PATCH 23/48] Redesign Challenge 03: car-wash reasoning task, base/premium terminology - Replace letter-count hard task with the car-wash reasoning trap (tracks capability monotonically; letter-count was a tokenization artifact that inverted across tiers) - Switch demo pair to Copilot-pickable gpt-4.1 (base) vs gpt-5 (premium); drop gpt-4.1-nano (not in the Copilot model picker) - Replace cheap/expensive with base/premium model terminology - Add Part 2 cost-of-retries reasoning and Part 4 classify-your-own-tasks - Add why-this-matters-for-coding and token-variance notes - Rebuild output-constraint demo on a verbose task (190->66 tok) - Update coach answer key, harness (carwash task), results, and TODO Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Coach/Solution-03.md | 133 +++++++++++------- .../README.md | 19 ++- .../TODO.md | 93 ++++++------ .../harness.py | 26 +++- .../results.md | 70 ++++++--- .../Student/Challenge-03.md | 116 ++++++++++----- .../Challenge-03-ModelSelection/README.md | 21 +-- .../measurements-template.md | 49 +++++-- .../output-constraints.md | 26 ++-- .../Challenge-03-ModelSelection/prompts.md | 36 +++-- 10 files changed, 388 insertions(+), 201 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md index c163cf1252..88431a28ff 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md @@ -5,96 +5,133 @@ ## Notes & Guidance This challenge teaches one durable idea: **total cost = token rate × tokens × attempts**, so -*cheap-per-token is not cheap-per-task.* Students prove it by running the same prompt on a -cheap and an expensive model across an **easy** task and a **hard** task, measuring outcome -and tokens. The magic is the contrast: opposite winners on the two tasks. +*lower cost per request is not lower cost per result.* Students prove it by running the same +prompt on a **base model** and a **premium model** across an **easy** task and a **hard** task, +measuring outcome and tokens. The magic is the contrast: opposite winners on the two tasks. + +> **Terminology:** we use **base model** (included, no premium-request multiplier — e.g. +> GPT-4.1, GPT-4o) and **premium model** (frontier/reasoning model billed as a premium request +> with a multiplier — e.g. GPT-5, Claude Sonnet, o-series). Avoid "cheap/expensive" with +> students — it's imprecise and the whole point is that "cheap" can be the costliest choice. ### The core mechanic -| | Easy task (version sort) | Hard task (letter count) | +| | Easy task (version sort) | Hard task (the car wash) | |---|---|---| -| Cheap model | ✅ correct, **fewer tokens** | ❌ confidently wrong, few tokens (a trap) | -| Strong model | ✅ correct, more tokens | ✅ correct, more tokens | -| **Lesson** | Use the cheap model → save credits | Cheap wrong answer is the costliest option → pay for capability | +| Base model | ✅ correct, **fewer tokens** | ❌ confidently wrong ("walk"), looks low-cost (a trap) | +| Premium model | ✅ correct, more tokens | ✅ correct ("drive"), more tokens | +| **Lesson** | Use the base model → save credits | Base model's wrong answer is the costliest option → pay for capability | ### Reference answer key (measured) -Measured via the GitHub Models inference API, **n=4 per cell** (see -`Solutions/Challenge-03-ModelSelection-Solutions/`). Exact numbers will vary by model/version; -the **pattern** is what matters. +Measured via the GitHub Models inference API, single-shot, **n=4 per cell** (see +`Solutions/Challenge-03-ModelSelection-Solutions/`). Exact numbers vary by model/version; the +**pattern** is what matters. | Model | Easy: pass rate | Easy: avg tokens | Hard: pass rate | Hard: avg tokens | |---|---|---|---|---| -| `gpt-4.1-nano` (cheap) | **4/4 (100%)** | ~93 | **0/4 (0%)** — always "4" | ~31 | -| `gpt-5` (strong) | **4/4 (100%)** | ~325 | **4/4 (100%)** | ~391 | +| `gpt-4.1` (base) | **4/4 (100%)** | ~106 | **0/4 (0%)** — answers "walk" | ~166 | +| `gpt-5` (premium) | **4/4 (100%)** | ~293 | **4/4 (100%)** — answers "drive" | ~1000 | Takeaways to draw out: -- Easy task: identical correct answer, but the cheap model used **~3.5× fewer tokens.** -- Hard task: the cheap model was wrong **every** time and *cheaper* — the low cost is - worthless because the answer is wrong. The strong model cost ~13× the cheap model's tokens - and was the only one correct. +- Easy task: identical correct answer, but the base model used **~2.8× fewer tokens.** +- Hard task: the base model was wrong **every** time (recommends walking, leaving the car at + home). It was not even lower-cost to be wrong here — and no number of retries reliably fixes a + reasoning-ceiling failure. The premium model was the only correct option. ### Why these specific tasks - **Version sort (easy):** real, practical, and both tiers get it right — so the only - differentiator is token cost. Clean "cheap wins" demonstration. -- **Letter counting (hard):** exploits a structural weakness (tokenization) that small models - reliably fail, and the answer is **human-verifiable in seconds** — students can *see* the - cheap model is wrong without trusting us. -- **Rejected:** the coin-change "greedy trap." We tested it — modern small models pass it, so - it does NOT discriminate. Don't use reasoning puzzles that cheap models have caught up on. - -### The "no retry" rule (important) - -Tell students explicitly: when the cheap model fails Part 2, **do not coach or retry it.** The -point is the first-shot outcome. In real workflows the hidden cost is the human time + extra -tokens spent discovering the answer is wrong and redoing it. Retrying hides that lesson. + differentiator is token cost. Clean "base model wins" demonstration. +- **The car wash (hard):** a pragmatic-reasoning trap. The "40 meters" bait makes base models + fixate on distance ("walk, it's greener") and miss that *the car must be present to be + washed.* The right answer (**drive**) is obvious to any human in a second — so students can + *see* the base model is wrong without trusting us. Crucially this tracks **capability**, so + results are monotonic with model strength. +- **Rejected — letter-counting / "gotcha" tasks** (e.g. "count the l's"): these are + **tokenization artifacts, not reasoning tests.** We measured them and results do **not** track + price — a base model can pass while a premium model fails (we observed Claude Haiku correct + and Claude Opus wrong on the same letter-count). That would teach the *opposite* of the + lesson. Do not use letter-counts, decimal-comparison, or "strawberry"-style traps. +- **Rejected — coin-change "greedy trap":** modern small models pass it; no longer discriminates. + +### The "no retry" rule, and the cost-of-retries reasoning (Part 2) + +Tell students explicitly: when the base model fails Part 2, **do not coach or retry it** for the +measurement. Then have them reason about retries: +- *How many base-model attempts would cost more than one premium call?* (Plug in token counts or + your org's multipliers.) +- *Would any number of attempts reliably get the right answer here?* (No — it's a capability + ceiling. This is the key insight: retrying the lower-cost model is throwing good money after + bad on tasks it can't reason through.) + +### Part 4 — classify your own tasks + +This is where the skill becomes transferable. Students write two real tasks from their own work, +predict the tier, run both, and check. Push them to articulate *why* a task is base- vs +premium-tier (well-defined/low-ambiguity vs multi-step reasoning/judgment) — that predictive +rule of thumb is the real deliverable. ## How students run it No codebase. Students use the **VS Code Copilot Chat model picker** to switch between a -cheap-tier and strong-tier model, paste the two prompts from +base-tier and premium-tier model, paste the two prompts from `Student/Resources/Challenge-03-ModelSelection/prompts.md`, and read tokens from the Output -panel / `/usage`. They fill in `measurements-template.md`. +panel / usage view. They fill in `measurements-template.md`. -> Orgs expose different models. Coach students to pick *any* cheap-tier vs strong-tier pair +> Orgs expose different models. Coach students to pick *any* base-tier vs premium-tier pair > their picker offers — the pattern holds. If your org only exposes one tier, use the coach -> answer key above as the demonstration. +> answer key above as the demonstration, or run the harness live. + +> **Token visibility caveat:** depending on Copilot version/org, the Output panel may not show a +> clean per-request token number. If so, students can still observe the *pattern* (premium model +> emits much more text). For exact counts, the coach harness (or the GitHub Models playground) +> reports `usage.total_tokens` directly. See `TODO.md` — aligning the token-measurement +> instructions across the whole hack (Challenge 00 sets this up) is tracked there. ## Expected Time ~45 minutes: -- 15 min: Part 1 (easy) on both models -- 15 min: Part 2 (hard) on both models +- 10 min: Part 1 (easy) on both models +- 10 min: Part 2 (hard) on both models + cost-of-retries reasoning - 10 min: Part 3 compare + discussion +- 10 min: Part 4 classify-your-own-tasks - 5 min: optional output-constraint run ## Success Criteria Validation -Students should produce a completed Part 3 table showing **opposite winners**: cheap model -wins the easy task on tokens; strong model is the only correct option on the hard task. Bonus: -a measurable token drop on the strong model when an output constraint is added to Part 1. +Students should produce a completed Part 3 table showing **opposite winners**: base model wins +the easy task on tokens; premium model is the only correct option on the hard task. They should +articulate the retry math (attempts-to-break-even) and the capability-ceiling point, and +classify two of their own tasks by tier. Bonus: a measurable token drop from an output +constraint on a verbose task. ## Common Blockers -- **Student retries the cheap model until it's right.** Stop them — that defeats the lesson. -- **Org exposes only one model tier.** Fall back to the answer key, or use the coach harness - to demo live. -- **Token counts not visible.** Ensure the GitHub Copilot extension is current and the Output - panel "GitHub Copilot Chat" channel is selected (covered in Challenge 00). -- **Cheap model happens to pass the hard task once.** It's stochastic; have them run it 2–3×. - It fails the large majority of the time. +- **Student retries the base model until it's right.** Stop them — that defeats the lesson. + Redirect to the cost-of-retries reasoning instead. +- **Base model happens to say "drive" once.** It's stochastic; have them run it 2–3×. It + recommends walking the large majority of the time. (If a student's base model reliably gets it + right, their "base" model may actually be fairly strong — have them drop to the smallest model + the picker offers.) +- **Org exposes only one model tier.** Fall back to the answer key, or use the coach harness. +- **Token counts not visible.** Premium model still visibly produces much more text — record the + pattern. For exact numbers use the harness. (See token-visibility caveat above.) +- **Premium model token counts vary a lot.** Reasoning models have variable hidden token use; + emphasize ratio/pattern over absolute numbers. ## Hints to Share -- "Cheap" is about *total* cost, not per-token price. A wrong answer you have to redo is the - most expensive outcome. -- Match the model to the task: cheap for well-defined/low-ambiguity work, strong for anything - needing real reasoning. +- "Base" vs "premium" is about *total* cost, not per-request price. A wrong answer you have to + redo is the costliest outcome. +- Match the model to the task: base for well-defined/low-ambiguity work, premium for anything + needing real reasoning or judgment. - Output constraints cut cost on any model — but they don't make a wrong model right. +- The car-wash distance is bait. The task is testing whether the model reasons about the *goal*. ## Reference Data & Reproduction See `Solutions/Challenge-03-ModelSelection-Solutions/`: - `harness.py` — measurement harness (counts pass/fail + tokens, with rate-limit backoff) - `results.md` — the measured tables above +- `TODO.md` — author follow-ups (token-measurement alignment, advanced/Auto-mode scope) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md index 8a4298c940..3ea11f9b54 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md @@ -9,6 +9,7 @@ VS Code Copilot Chat model picker + Output panel. |---|---| | `harness.py` | Measurement harness: runs N trials of each (model, task), counts pass/fail, averages tokens, with rate-limit backoff | | `results.md` | The measured answer-key tables referenced in `Solution-03.md` | +| `TODO.md` | Author follow-ups / deferred enhancements | ## Running the harness @@ -16,15 +17,25 @@ The harness calls the **GitHub Models inference API** and authenticates with you `gh auth token`. ```bash -# default: gpt-4.1-nano vs gpt-5, both tasks, n=4 -python harness.py --models "openai/gpt-4.1-nano" "openai/gpt-5" --tasks sort letter -n 4 --sleep 2 +# default: gpt-4.1 (base) vs gpt-5 (premium), both tasks, n=4 +python harness.py --models "openai/gpt-4.1" "openai/gpt-5" --tasks sort carwash -n 4 --sleep 2 ``` Output is a summary table of pass rate + average tokens per (model, task), and a `results.json` dump. +### Tasks + +- `sort` — easy (version sort). Both tiers pass; the differentiator is tokens. +- `carwash` — hard (the "walk or drive to the car wash" trap). Base models recommend *walking* + (wrong); premium models recommend *driving* (correct). The `carwash` check marks an answer + correct when the model's leading recommendation is to **drive**. + ### Notes + - The free GitHub Models tier is rate-limited; the harness backs off on HTTP 429. For large N, expect it to run slowly. n=4 is sufficient to demonstrate the pattern. -- Strong models (e.g. `gpt-5`) throttle the most. Increase `--sleep` if you see many retries. -- `--tasks` accepts `sort` (easy) and `letter` (hard). +- Premium models (e.g. `gpt-5`) throttle the most. Increase `--sleep` if you see many retries. +- Premium reasoning models also produce highly variable token counts — focus on the pattern. +- **Do not use temperature with `gpt-5`** via this API — it rejects non-default temperature + (HTTP 400). The harness omits the temperature parameter for this reason. diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md index e9fdfcc529..904192ccfe 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md @@ -1,49 +1,48 @@ -# Challenge 03 — Deferred Enhancements (TODO) - -Coach/author notes. The challenge as committed is **complete and runnable**, but a review -(walking it against Challenges 01/02 and running it live) flagged that the *concept* is strong -while the *activity* is light (~10 min: 4 prompts + a table) compared to C01/C02 (30–60 min of -hands-on building). The items below would bring it to C01-level depth without losing the crisp -"cheap-per-token ≠ cheap-per-task" framing. Handle in a follow-up. - -## A. Add activity depth (fills the 45-min slot) -- [ ] "**Classify your own task**" exercise: student writes 2 real tasks from their own work, - predicts easy→cheap vs hard→strong, runs each on both model tiers, and checks the - prediction. Makes the lesson personal and transferable. -- [ ] Add an **Advanced Challenges** section (C01 has one; C03 currently doesn't): - - Try a **mid-tier / reasoning-tier** model on the hard task — where's the price/capability knee? - - Build a **two-model workflow**: cheap model drafts, strong model reviews — measure total cost. - - Try **Auto mode** (if the org exposes it) and compare routing + cost to manual selection. - -## B. Pre-empt the "gotcha" objection -- [ ] Add ~1 paragraph: the letter-count task tests the model's **direct reasoning**, not its - ability to emit code. A sharp student will say "I'd just have it write code to count." - Connect it to agentic coding: the model constantly reasons *within* tasks (choosing logic, - comparing values, judging correctness) — and that is exactly where a weak model is - confidently wrong. Model selection governs reasoning quality, not just code emission. - -## C. Token-count variance note -- [ ] Add a note in the student doc: token counts vary run-to-run (strong models especially — - reasoning tokens). Observed gpt-5 on the easy task: 229 / 325 / 357 tokens across runs. - Tell students to **focus on the pattern / ratio, not the absolute number**, and to run a - task 2–3× if a result looks anomalous. - -## D. Scope decision (was in the ORIGINAL Challenge-03, dropped in the rewrite) -- [ ] Decide whether to re-add, likely as **optional/Advanced**: - - **Reasoning levels** — compare credit use across reasoning-effort settings. - - **Auto mode** — when automatic routing beats manual model choice (original success criterion - was "Explain when Auto mode provides value vs. manual selection"). -- Options discussed: (1) re-add both as Advanced, (2) leave out for focus, (3) add Auto mode only. - Pending owner sign-off. - -## Validated data (do not lose — basis for the answer key) -Measured via GitHub Models API (`harness.py`), single-shot, no retries: - -| Model | Easy (version sort) | Hard (letter count) | +# Challenge 03 — Author TODO / Deferred + +Coach/author notes. The challenge is complete and runnable. This tracks follow-ups. + +## Done (this revision) +- [x] **Replaced the hard task** from letter-counting → the **car wash** ("walk or drive 40 m + to wash my car"). Letter-counting was a tokenization artifact whose results did **not** + track price (base model could beat premium — we observed Haiku right / Opus wrong). The + car wash tracks capability and is monotonic. See `results.md`. +- [x] **Switched the base/premium pair** to Copilot-pickable models. The old `gpt-4.1-nano` + reliably failed the hard task but is **not selectable in the Copilot model picker**, so + students couldn't use it. New pair: base `gpt-4.1`, premium `gpt-5`. +- [x] **Terminology:** removed "cheap/expensive"; now **base model** / **premium model** + (matches Copilot's included-vs-premium-request billing language). +- [x] **Added depth:** Part 2 cost-of-retries reasoning ("how many base attempts to exceed one + premium call?" + capability-ceiling point); Part 4 "classify your own tasks"; a + "why this matters for coding" paragraph; a token-variance note. +- [x] **Output-constraint section** rebuilt around a verbose task (palindrome function, + 190→66 tok on gpt-4.1) — the old version-sort example showed no reduction. + +## Open +- [ ] **Token-measurement alignment (hack-wide).** The student docs point to + `View → Output → "GitHub Copilot Chat"` / usage view for token counts, per Challenge 00's + setup. Verify that Copilot Chat actually surfaces a clean per-request token number in the + target VS Code/Copilot version. If it does **not**, this is a **Challenge 00** problem + affecting every challenge — fix it there (or standardize on a token source) rather than + only in Challenge 03. Coach harness + GitHub Models playground are reliable fallbacks. +- [ ] **Advanced section (optional).** Add an "Advanced Challenges" block: try a mid-tier / + reasoning model on the hard task (where's the price/capability knee?); build a two-model + "base drafts → premium reviews" workflow and measure total cost. +- [ ] **Scope decision — reasoning levels + Auto mode.** The *original* Challenge-03 included + comparing reasoning-effort levels and explaining when **Auto mode** beats manual + selection. Decide whether to re-add as optional/Advanced. Needs owner sign-off. + +## Validated data (basis for the answer key) +Measured via GitHub Models API (`harness.py`), single-shot, no retries, n=4: + +| Model | Easy (version sort) | Hard (car wash) | |---|---|---| -| gpt-4.1-nano (cheap) | ✅ 4/4 pass, ~93 tok | ❌ 0/4 pass, ~31 tok (always "4") | -| gpt-5 (strong) | ✅ 4/4 pass, ~229–357 tok | ✅ 4/4 pass, ~295–391 tok | +| gpt-4.1 (base) | ✅ 4/4, ~106 tok | ❌ 0/4 — says "walk", ~166 tok | +| gpt-5 (premium) | ✅ 4/4, ~293 tok | ✅ 4/4 — says "drive", ~1000 tok | + +Output constraint (gpt-4.1, palindrome function): ~190 → ~66 tok = **−65%**, identical code. +Constraint showed **no** effect on the terse sort task and on gpt-5 (reasoning tokens dominate). -Output constraint (gpt-5, easy task): 229 → 169 tok = **−26%**, identical answer. -Rejected: ministral-3b (too weak — fails the easy task); coin-change greedy trap (modern small -models pass it — no longer discriminates). +Rejected: letter-count/decimal/"strawberry" (tokenization artifacts — don't track price); +`ministral-3b` (fails easy task too); `gpt-4.1-nano` (not in Copilot picker); coin-change +greedy trap (modern small models pass it). diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py index 54f921622c..4e08f491f1 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py @@ -21,8 +21,8 @@ SORT_PROMPT = ("Sort these software version numbers from oldest to newest and " "list them in order separated by commas: 1.9.0, 1.10.0, 1.2.0, " "1.11.0, 1.9.5") -LETTER_PROMPT = ("How many times does the letter l appear in the phrase " - "'parallel lullaby'? Answer with only the number.") +CARWASH_PROMPT = ("The car wash is 40 meters from my home. I want to wash my " + "car. Should I walk or drive there?") def check_sort(ans: str) -> bool: @@ -30,14 +30,26 @@ def check_sort(ans: str) -> bool: return versions == ["1.2.0", "1.9.0", "1.9.5", "1.10.0", "1.11.0"] -def check_letter(ans: str) -> bool: - m = re.search(r"\d+", ans) - return m is not None and m.group() == "6" +def check_carwash(ans: str) -> bool: + """Correct iff the model recommends DRIVING (the car must be at the wash). + + Heuristic: look at the opening recommendation. Premium models lead with + 'Drive...'; base models lead with 'Walk...' / 'Walking...'. We treat the + first mention of walk/drive as the recommendation. + """ + low = ans.lower() + di = low.find("driv") + wi = low.find("walk") + if di == -1: + return False + if wi == -1: + return True + return di < wi TASKS = { "sort": {"prompt": SORT_PROMPT, "check": check_sort}, - "letter": {"prompt": LETTER_PROMPT, "check": check_letter}, + "carwash": {"prompt": CARWASH_PROMPT, "check": check_carwash}, } @@ -100,7 +112,7 @@ def run(token: str, model: str, task_key: str, n: int, sleep: float): def main() -> None: ap = argparse.ArgumentParser() ap.add_argument("--models", nargs="+", required=True) - ap.add_argument("--tasks", nargs="+", default=["sort", "letter"]) + ap.add_argument("--tasks", nargs="+", default=["sort", "carwash"]) ap.add_argument("-n", type=int, default=50) ap.add_argument("--sleep", type=float, default=1.0) args = ap.parse_args() diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md index 4bba38dbd8..b488378bd6 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md @@ -3,34 +3,72 @@ Source: GitHub Models inference API. Method: `harness.py`, **n=4 trials per (model, task)**, single-shot (no retries). Exact token counts vary by model version; the **pattern is stable.** +Models used as the demonstration pair: +- **Base:** `openai/gpt-4.1` (included tier, no premium multiplier — pickable in Copilot Chat) +- **Premium:** `openai/gpt-5` (frontier/reasoning tier) + ## Summary | Model | Task | Pass rate | Avg total tokens | |---|---|---|---| -| `openai/gpt-4.1-nano` (cheap) | sort (easy) | **4/4 — 100%** | 93 | -| `openai/gpt-4.1-nano` (cheap) | letter (hard) | **0/4 — 0%** (always "4") | 31 | -| `openai/gpt-5` (strong) | sort (easy) | **4/4 — 100%** | 325 | -| `openai/gpt-5` (strong) | letter (hard) | **4/4 — 100%** | 391 | +| `openai/gpt-4.1` (base) | sort (easy) | **4/4 — 100%** | ~106 | +| `openai/gpt-4.1` (base) | car wash (hard) | **0/4 — 0%** (answers "walk") | ~166 | +| `openai/gpt-5` (premium) | sort (easy) | **4/4 — 100%** | ~293 | +| `openai/gpt-5` (premium) | car wash (hard) | **4/4 — 100%** (answers "drive") | ~1000 | ## Interpretation -- **Easy task (version sort):** both models 100% correct. The cheap model produced the - identical answer using **~3.5× fewer tokens** (93 vs 325). Paying for the strong model here - buys nothing → **use the cheap model.** -- **Hard task (letter count):** the cheap model was **wrong every single time** (always "4") - and was *cheaper* in tokens — the low cost is a trap because the output is useless. The - strong model was the only correct option, at ~13× the cheap model's token cost → - **pay for capability.** +- **Easy task (version sort):** both models 100% correct. The base model produced the identical + answer using **~2.8× fewer tokens** (106 vs 293). Paying for the premium model here buys + nothing → **use the base model.** +- **Hard task (the car wash):** the base model recommended **walking** every single time — + fixating on "40 meters" and missing that the car has to be *at* the wash. The premium model + reasoned about the goal and answered **drive** every time. Retrying the base model can't fix + this — it's a reasoning ceiling → **pay for capability.** + +## Monotonicity check (why the car wash, not letter-counting) + +We require a task where success tracks **capability** (and therefore price). The car wash does; +tokenization "gotchas" do not. Measured examples: + +| Task | gpt-4o-mini (base) | gpt-4.1 (base) | gpt-5 (premium) | Tracks capability? | +|---|---|---|---|---| +| Car wash (walk/drive) | ❌ walk | ❌ walk | ✅ drive | ✅ yes — monotonic | +| Letter count ("l" in "parallel lullaby") | mixed | ✅ 6 | ✅ 6 | ❌ no — base passes | +| Letter count (Claude, observed in Copilot) | Haiku ✅ | — | Opus ❌ | ❌ no — **inverts** | + +The letter-count row is why we dropped it: a base model (Haiku) was correct while a premium +model (Opus) was wrong — the opposite of the lesson. Letter-counting, decimal comparison, and +"strawberry"-style tasks are tokenization artifacts and must not be used here. + +## Output constraint (optional section) + +Constraints reduce **output** tokens, so they show best on a **verbose-by-default** task, on a +non-reasoning (base) model. Measured on `openai/gpt-4.1`: + +| Prompt | Avg total tokens | +|---|---| +| "Write a Python function that checks whether a string is a palindrome." | ~190 | +| same + "Output only the code. No explanation, no markdown fences." | ~66 | + +→ **~65% fewer tokens** for the identical function. + +Note: the constraint did **not** help on the already-terse version-sort task (~103 → ~104 on +gpt-4.1), and did not reduce `gpt-5`'s totals (reasoning/"thinking" tokens dominate and aren't +constrained). Pick a verbose task to demonstrate the lever. -## Models we evaluated and rejected as the "cheap" pick +## Models / tasks we evaluated and rejected -| Model | Why rejected | +| Candidate | Why rejected | |---|---| -| `mistral-ai/ministral-3b` | Too weak — failed the **easy** task (2/8), breaking the "cheap wins Part 1" story | -| coin-change "greedy trap" task | Modern small models pass it — no longer discriminates; replaced with letter counting | +| `mistral-ai/ministral-3b` as the base pick | Too weak — failed the **easy** task too, breaking the "base wins Part 1" story | +| `gpt-4.1-nano` as the base pick | Reliably fails the hard task, **but is not selectable in the Copilot model picker** — students can't use it | +| Letter-count / decimal / "strawberry" tasks | Tokenization artifacts — results don't track price (base can beat premium); see monotonicity table | +| Coin-change "greedy trap" | Modern small models pass it — no longer discriminates | ## Reproduce ```bash -python harness.py --models "openai/gpt-4.1-nano" "openai/gpt-5" --tasks sort letter -n 4 --sleep 2 +# easy + hard, base vs premium, n=4 +python harness.py --models "openai/gpt-4.1" "openai/gpt-5" --tasks sort carwash -n 4 --sleep 2 ``` diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md index 9e3c1c1802..1618e648d0 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md @@ -8,28 +8,34 @@ Not every task needs the most powerful model. Under usage-based billing, cost is > **Total cost = token rate × tokens × attempts** -That last term — *attempts* — is the one people forget. A cheap model that answers a simple task correctly in a few tokens is a bargain. But that same cheap model, set loose on a task it cannot actually reason through, will hand you a **confident, wrong answer**. Now you are paying again (and again) to notice it is wrong and redo the work. The "cheap" model just became the expensive one. +That last term — *attempts* — is the one people forget. A **base model** that answers a simple task correctly in a few tokens is a bargain. But that same base model, set loose on a task it cannot actually reason through, will hand you a **confident, wrong answer**. Now you are paying again (and again) to notice it is wrong and redo the work. The model that looked lower-cost per request just became the costliest one. -In this challenge you will run the **same prompt against a cheap model and an expensive model — twice.** First on an **easy** task, then on a **hard** task. Every run, you measure two things: **the outcome (did it get it right?)** and **the token cost**. From that data you will build the skill this challenge is really about: deciding *which model to use for which job.* +In this challenge you will run the **same prompt against a base model and a premium model — twice.** First on an **easy** task, then on a **hard** task. Every run, you measure two things: **the outcome (did it get it right?)** and **the token cost**. From that data you will build the skill this challenge is really about: deciding *which model to use for which job.* -> **Key Concept:** Cheap-per-token is not the same as cheap-per-task. +> **Key Concept:** Lower cost per request is not the same as lower cost per *result*. + +### Why this matters for coding + +This challenge uses two short, easy-to-check prompts so the difference is obvious in seconds. But the lesson is the same one you face every time you code with Copilot: an agent constantly **reasons inside a task** — choosing logic, comparing values, judging whether its own output is correct. That is exactly where a weaker model is *confidently wrong*. Model selection governs the quality of that reasoning, not just whether code comes out. Pick the model that fits the *thinking* the task requires. ## Description You will run **two tasks**, each against **two models**: -- A **cheap / lightweight model** — e.g. a "mini", "nano", "Haiku", or "Flash" tier model -- An **expensive / frontier model** — e.g. a GPT-5, Claude Sonnet, or o-series tier model +- A **base model** — included with your subscription, no premium-request multiplier (e.g. GPT-4.1, GPT-4o). Fast and economical. +- A **premium model** — a frontier / reasoning model billed as a premium request with a cost multiplier (e.g. GPT-5, Claude Sonnet, an o-series model). + +> Use whatever base-tier and premium-tier models your organization exposes in the GitHub Copilot Chat **model picker**. The exact names don't matter — the *pattern* does. The picker shows a multiplier (e.g. `1×`) next to premium models; base models show no multiplier. -> Use whatever cheap-tier and strong-tier models your organization exposes in the GitHub Copilot Chat **model picker**. The exact names don't matter — the *pattern* does. +For every run, record the **outcome** (correct / incorrect) and the **token usage** (`View → Output → "GitHub Copilot Chat"`, and/or your Copilot usage view). If your environment doesn't surface an exact per-request token count, you can still see the pattern: the premium model produces far more text. Note *roughly how much more*. -For every run, record the **outcome** (correct / incorrect) and the **token usage** from the VS Code Output panel (`View → Output → "GitHub Copilot Chat"`) and/or `/usage`. +> **Rule — no retries:** When the base model gets it wrong, **do not coach it or try again.** Record the failure and move on. The whole point is to see what each model produces *on the first shot* for each kind of task. (You'll reason about the cost of retrying in Part 2.) -> **Rule — no retries:** When the cheap model gets it wrong, **do not coach it or try again.** Record the failure and move on. The whole point is to see what each model produces *on the first shot* for each kind of task. +> **A note on token counts:** Exact token numbers vary run to run — premium reasoning models especially. Focus on the **pattern and the ratio**, not the absolute number. If a result looks odd, run it 2–3 times. --- -## Part 1 — An Easy Task (the cheap model should win) +## Part 1 — An Easy Task (the base model should win) Give **both** models this exact prompt: @@ -42,42 +48,53 @@ order separated by commas: 1.9.0, 1.10.0, 1.2.0, 1.11.0, 1.9.5 ### Record -| | Cheap model | Expensive model | +| | Base model | Premium model | |---|---|---| | Correct? | ? | ? | | Total tokens | ? | ? | ### What to notice -Both models should get this right. Now compare the **token counts**. The expensive model often produces far more output — restated reasoning, explanations — for the *exact same correct answer*. On an easy task, that extra spend buys you nothing. +Both models should get this right. Now compare the **token counts**. The premium model often produces far more output — restated reasoning, explanations — for the *exact same correct answer*. On an easy task, that extra spend buys you nothing. --- -## Part 2 — A Hard Task (the cheap model should fail) +## Part 2 — A Hard Task (the base model should fail) Now give **both** models this exact prompt: ``` -How many times does the letter l appear in the phrase 'parallel lullaby'? -Answer with only the number. +The car wash is 40 meters from my home. I want to wash my car. +Should I walk or drive there? ``` -✅ Correct answer: `6` (count them yourself: para**ll**e**l** = 3, **l**u**ll**aby = 3) +✅ Correct answer: **Drive.** You can't wash a car that isn't there — the car has to be *at* the car wash. Walking the 40 meters leaves your car (and the problem) at home. The distance is a deliberate distraction. ### Record -| | Cheap model | Expensive model | +| | Base model | Premium model | |---|---|---| +| Answer (walk / drive) | ? | ? | | Correct? | ? | ? | | Total tokens | ? | ? | ### What to notice -The cheap model will likely answer **confidently and incorrectly** (a very common answer is `4`). You can verify the right answer yourself in seconds — *that is the point.* The wrong answer is also **cheap in tokens**, which is exactly the trap: low token cost, zero value. +The base model will very likely tell you to **walk** — "it's only 40 meters, it's greener, you'll get some exercise." It latches onto the short distance and misses the obvious point: *the car needs to come with you.* It is **confidently wrong**, and you can see it's wrong in one second — *that is the point.* + +The premium model reasons about the actual goal ("the car has to be at the wash to be cleaned → drive") and gets it right. Those extra tokens are not waste — they are the price of a *correct* answer. + +> Record the base model's wrong answer and stop — **don't rerun or rephrase it.** That single result is all you need. The next section is a calculation, not another run. -The expensive model gets it right, and costs **more** tokens to do so. For this kind of task, those extra tokens are not waste — they are the price of a *correct* answer. +### The cost of "just trying again" -> Do **not** retry the cheap model. A wrong answer is the result. In the real world, the hidden cost of a cheap wrong answer is the time and tokens you burn discovering it is wrong and redoing the work. +You won't actually retry here — but it's worth reasoning about, because in real work the temptation is "the base model costs less per call, I'll just rerun or rephrase until it gets it." Using the numbers you **already recorded above**: + +1. Take the base model's per-attempt cost and the cost of **one** premium-model call (use your org's per-request multipliers, or the token counts you just measured). + > **How many base-model attempts would it take to cost more than one premium-model call?** +2. Now the harder question: on a task like this — where the base model hits a **reasoning ceiling** — *would any number of attempts reliably get you the right answer?* (You already saw its single answer; capability, not luck, is the limit.) + +The trap: you could burn several low-cost attempts, pass the cost of one premium call, **and still not have a correct answer.** For a task the base model can't reason through, the only fix is a more capable model — not more attempts. --- @@ -85,40 +102,67 @@ The expensive model gets it right, and costs **more** tokens to do so. For this Combine your measurements into one table: -| Task | Cheap: correct? | Cheap: tokens | Strong: correct? | Strong: tokens | Which model should you use? | -|------|-----------------|---------------|------------------|----------------|-----------------------------| +| Task | Base: correct? | Base: tokens | Premium: correct? | Premium: tokens | Which model should you use? | +|------|----------------|--------------|-------------------|-----------------|-----------------------------| | Part 1 (easy) | ? | ? | ? | ? | ? | | Part 2 (hard) | ? | ? | ? | ? | ? | ### Questions to Answer 1. On the **easy** task, which model gave the better *value* (correct answer, fewest tokens)? -2. On the **hard** task, what did the cheap model's wrong answer actually "cost" you — even though it used fewer tokens? +2. On the **hard** task, what did the base model's wrong answer actually "cost" you, even though each attempt was low-cost? 3. If you ran each task **10,000 times a day**, how would your model choice differ between Part 1 and Part 2? -4. How would you decide, *before* running a task, whether it is a "Part 1" (easy → cheap) task or a "Part 2" (hard → strong) task? +4. How would you decide, *before* running a task, whether it is a "Part 1" (easy → base) or a "Part 2" (hard → premium) task? + +--- + +## Part 4 — Classify Your Own Tasks + +The skill this challenge builds is *prediction*: knowing which tier a task needs **before** you spend anything. + +1. Write down **two real tasks** from your own work — one you think a base model can handle, one you think needs a premium model. +2. For each, predict the tier and **why** (Is it well-defined, or does it need multi-step reasoning / judgment?). +3. Run each task on **both** tiers and check your prediction. Were you right? Note any surprises. + +| Your task | Predicted tier | Actual best tier | Was your prediction right? | +|---|---|---|---| +| 1. | | | | +| 2. | | | | --- ## Optional — Output Constraints -Output tokens usually cost more than input tokens. Re-run **Part 1 with the expensive model**, but add an output constraint to the prompt: +Output tokens usually cost more than input tokens, and constraining what a model *produces* is a lever you control on **every** model. + +Pick a task where the model is **verbose by default** — for example, asking for a small function: ``` -...Answer with only the comma-separated list and nothing else. +Write a Python function that checks whether a string is a palindrome. ``` -Record the token difference vs. your earlier Part 1 run. Constraining output — "answer only", "code only", "explain in under 50 words", or a JSON schema — is a lever you control on **every** model, cheap or expensive. +Run it on the base model, then run it again with an output constraint added: + +``` +Write a Python function that checks whether a string is a palindrome. +Output only the code. No explanation, no markdown fences. +``` + +Record the token difference. Constraining output — "code only", "answer only", "explain in under 50 words", a JSON schema — drops the cost while keeping the correct result. + +> Note: constraints reduce **output** tokens. They help most when the model would otherwise pad the answer with explanation. They do **not** make a wrong model right (see Part 2), and they do little when the output is already terse or when a reasoning model's hidden "thinking" tokens dominate. ## Success Criteria To complete this challenge successfully, you should be able to: -- Run the same prompt against a cheap and an expensive model for both tasks +- Run the same prompt against a base and a premium model for both tasks - Record outcome (correct/incorrect) and token usage for all four runs -- Show that on the easy task the cheap model was correct **and** cheaper -- Show that on the hard task the cheap model was confidently wrong while the expensive model was correct -- Demonstrate a token reduction on the expensive model by adding an output constraint -- Articulate a rule of thumb for deciding which model to use for a given task +- Show that on the easy task the base model was correct **and** used fewer tokens +- Show that on the hard task the base model was confidently wrong while the premium model was correct +- Reason about how many base-model retries it would take to cost more than one premium call — and why retries can't fix a reasoning-ceiling task +- Classify two of your own real tasks by tier and verify your prediction +- (Optional) Demonstrate a token reduction by adding an output constraint to a verbose task ## Learning Resources @@ -128,14 +172,14 @@ To complete this challenge successfully, you should be able to: ## Tips -- Cost = token rate × tokens × **attempts**. A cheap *wrong* answer can be the most expensive option. -- The cheap model is great for well-defined, low-ambiguity work — and it is wasteful to *avoid* it there. -- The expensive model earns its price on tasks that need real reasoning, where a wrong first answer is costly. +- Cost = token rate × tokens × **attempts**. A *wrong* answer you have to chase down is the costliest option. +- The base model is great for well-defined, low-ambiguity work — and it is wasteful to *avoid* it there. +- The premium model earns its multiplier on tasks that need real reasoning, where a wrong first answer is costly. - Output constraints reduce cost on *any* model — ask for the answer only when you don't need narration. - The best model is not the smartest one — it is the one that returns a *correct* answer at the lowest total cost. ## Reflection Questions 1. Describe a real task from your own work that is a "Part 1" task. Which model would you use and why? -2. Describe a real "Part 2" task. How would you justify the higher per-token cost to your team? -3. How could you combine cheap and expensive models in a single workflow to minimize total cost (e.g., cheap model drafts, strong model reviews)? +2. Describe a real "Part 2" task. How would you justify the premium multiplier to your team? +3. How could you combine base and premium models in a single workflow to minimize total cost (e.g., base model drafts, premium model reviews)? diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md index 62d16eecaf..88140c3f47 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md @@ -15,14 +15,19 @@ comes back. ## How to run it (VS Code + GitHub Copilot Chat) 1. Open GitHub Copilot Chat in VS Code. -2. Use the **model picker** to select a **cheap-tier** model (e.g. a "mini" / "nano" / - "Haiku" / "Flash" model your org exposes). +2. Use the **model picker** (bottom of the chat box) to select a **base-tier** model — one with + *no* premium-request multiplier (e.g. GPT-4.1 / GPT-4o). 3. Paste a prompt from `prompts.md` exactly as written. Record the answer and the token - usage from `View → Output → "GitHub Copilot Chat"` (and/or `/usage`). -4. Switch the model picker to an **expensive-tier** model (e.g. GPT-5 / Sonnet / o-series) - and run the **same** prompt. Record again. + usage (`View → Output → "GitHub Copilot Chat"`, and/or your Copilot usage view). +4. Switch the model picker to a **premium-tier** model — one that shows a cost multiplier + (e.g. GPT-5 / Claude Sonnet / an o-series model) — and run the **same** prompt. Record again. 5. Repeat for both the easy and the hard prompt. -6. Fill in `measurements-template.md` and answer the Part 3 questions. +6. Fill in `measurements-template.md` and answer the Part 3 questions, then do the Part 4 + "classify your own tasks" exercise. -> **Rule:** Do not retry or coach the cheap model when it gets the hard task wrong. A wrong -> first answer is a valid — and important — result. +> **Rule:** Do not retry or coach the base model when it gets the hard task wrong. A wrong +> first answer is a valid — and important — result. You'll reason about the cost of retrying +> in Part 2 instead. + +> **If your picker shows only one tier:** ask your coach which models map to "base" and +> "premium" for your org, or use the coach's reference numbers as the demonstration. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md index 8ea07ec938..5bf1dccafa 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md @@ -1,18 +1,22 @@ # Challenge 03 — Measurement Template Fill in the tables as you run each prompt. Get token counts from -`View → Output → "GitHub Copilot Chat"` and/or `/usage`. +`View → Output → "GitHub Copilot Chat"` and/or your Copilot usage view. If exact per-request +counts aren't shown, record *roughly* how much more text the premium model produced. -Record the **cheap-tier** and **strong-tier** model names you actually used: +> Token counts vary run to run (premium reasoning models especially). Focus on the **pattern / +> ratio**, not the absolute number. -- Cheap model: `____________________` -- Strong model: `____________________` +Record the **base-tier** and **premium-tier** model names you actually used: + +- Base model: `____________________` +- Premium model: `____________________` --- ## Part 1 — Easy task (version sort) -| | Cheap model | Strong model | +| | Base model | Premium model | |---|---|---| | Answer given | | | | Correct? (Y/N) | | | @@ -22,21 +26,27 @@ Record the **cheap-tier** and **strong-tier** model names you actually used: --- -## Part 2 — Hard task (letter count) +## Part 2 — Hard task (the car wash) -| | Cheap model | Strong model | +| | Base model | Premium model | |---|---|---| -| Answer given | | | +| Answer (walk / drive) | | | | Correct? (Y/N) | | | | Total tokens | | | -**Observation:** _Did the cheap model fail? Was its wrong answer "cheap"?_ +**Observation:** _Did the base model say "walk"? Each attempt was low-cost — but was it useful?_ + +### Cost-of-retries reasoning + +- Base model cost per attempt: `__________` | Premium model cost (one call): `__________` +- **How many base-model attempts equal one premium call?** `__________` +- On this task, would *any* number of base-model attempts reliably get the right answer? `__________` --- -## Optional — Output constraint (Part 1, strong model) +## Optional — Output constraint (verbose task, base model) -| | Strong model (no constraint) | Strong model (answer-only) | +| | Base model (no constraint) | Base model (code/answer only) | |---|---|---| | Total tokens | | | | Token reduction | — | | @@ -45,14 +55,23 @@ Record the **cheap-tier** and **strong-tier** model names you actually used: ## Part 3 — Decision table -| Task | Cheap correct? | Cheap tokens | Strong correct? | Strong tokens | Use which model? | -|------|----------------|--------------|-----------------|---------------|------------------| +| Task | Base correct? | Base tokens | Premium correct? | Premium tokens | Use which model? | +|------|---------------|-------------|------------------|----------------|------------------| | Part 1 (easy) | | | | | | | Part 2 (hard) | | | | | | ### Answers 1. Easy task — better value (correct + fewest tokens)? → -2. Hard task — what did the cheap wrong answer really cost? → +2. Hard task — what did the base model's wrong answer really cost? → 3. At 10,000 runs/day, how does your choice differ for Part 1 vs Part 2? → -4. How do you decide *up front* whether a task is "easy → cheap" or "hard → strong"? → +4. How do you decide *up front* whether a task is "easy → base" or "hard → premium"? → + +--- + +## Part 4 — Classify your own tasks + +| Your task | Predicted tier | Actual best tier | Prediction right? | +|---|---|---|---| +| 1. | | | | +| 2. | | | | diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md index 4ce107ac1e..6407b380c4 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md @@ -14,15 +14,25 @@ a cost lever you control on **every** model. Use these patterns when you don't n ## Why it matters -A strong model asked an easy question will often spend most of its tokens *explaining* an -answer you already trust. The constraint keeps the correctness and drops the cost. +A model asked a question it would normally *explain* will spend most of its tokens narrating an +answer you already trust. The constraint keeps the correctness and drops the cost. The effect is +biggest on **verbose-by-default** tasks (e.g. "write a function") — there the model otherwise +wraps the answer in explanation and markdown. ## Try it -Take any Part 1 run on the strong model and re-run it with `"Answer with only the -comma-separated list and nothing else."` appended. Compare total tokens — the answer is -identical, the cost is lower. +Take a verbose task on the base model and re-run it with an output constraint appended: -> Note: constraints reduce **output** tokens. They do not fix a model that is *wrong* -> (see Part 2). For a task the cheap model can't reason through, a constraint just gives you -> a wrong answer faster — model selection, not output shape, is the fix there. +``` +Write a Python function that checks whether a string is a palindrome. +Output only the code. No explanation, no markdown fences. +``` + +Compare total tokens — the code is identical, the cost is much lower. + +> Notes: +> - Constraints reduce **output** tokens. They do little when the output is already terse +> (e.g. a one-line answer) or when a reasoning model's hidden "thinking" tokens dominate. +> - Constraints do **not** fix a model that is *wrong* (see Part 2). For a task the base model +> can't reason through, a constraint just gives you a wrong answer faster — model selection, +> not output shape, is the fix there. diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md index 10962b6a60..75aa0afcb8 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md @@ -15,30 +15,42 @@ order separated by commas: 1.9.0, 1.10.0, 1.2.0, 1.11.0, 1.9.5 ✅ **Correct answer:** `1.2.0, 1.9.0, 1.9.5, 1.10.0, 1.11.0` A wrong answer usually sorts the versions as text (so `1.10.0` and `1.11.0` land before -`1.9.0`). Modern models — cheap or strong — almost always get this right. +`1.9.0`). Modern models — base or premium — almost always get this right. The differentiator +here is **token cost**, not correctness. --- -## Part 2 — Hard task (letter count) +## Part 2 — Hard task (the car wash) ``` -How many times does the letter l appear in the phrase 'parallel lullaby'? -Answer with only the number. +The car wash is 40 meters from my home. I want to wash my car. +Should I walk or drive there? ``` -✅ **Correct answer:** `6` +✅ **Correct answer:** **Drive.** You can't wash a car that isn't there — the car has to be +*at* the car wash. The "40 meters" is a deliberate distraction; the base model tends to fixate +on the short distance and tell you to **walk** (leaving your car, and the whole point, at home). -Count it yourself: `para`**`l`**`` `l` ``e`**`l`** → 3, and `` `l` ``u`**`l`**`l`aby → 3. -A cheap model very commonly answers `4` — confidently, and in very few tokens. +A premium model reasons about the actual goal — *the car must be present to be washed* — and +answers **drive**. The wrong answer is obvious to any human in one second: that is exactly why +this task works. --- -## Optional — Output constraint variant (Part 1, strong model) +## Optional — Output constraint variant (verbose coding task) + +Pick a task the model is verbose about by default, then constrain the output: + +``` +Write a Python function that checks whether a string is a palindrome. +``` + +then ``` -Sort these software version numbers from oldest to newest: 1.9.0, 1.10.0, 1.2.0, -1.11.0, 1.9.5. Answer with only the comma-separated list and nothing else. +Write a Python function that checks whether a string is a palindrome. +Output only the code. No explanation, no markdown fences. ``` -Same task, but the constraint suppresses the explanation the strong model would otherwise -produce. Compare the token count to your original Part 1 run with the same model. +Run both on the **base model** and compare total tokens. The code is the same; the constrained +run drops the surrounding explanation, cutting cost. From b66336e1f0db777e0dd292c6e6f630f64d438768 Mon Sep 17 00:00:00 2001 From: Devanshi <devanshi.thakar123@gmail.com> Date: Tue, 30 Jun 2026 17:51:53 -0400 Subject: [PATCH 24/48] added a more bloated instructions file and updated events files --- .../.github/copilot-instructions.md | 7 +- .../.github/instructions/api.instructions.md | 8 +- .../instructions/events.instructions.md | 10 +- .../skills/free-events-endpoint/SKILL.md | 13 +- .../src/data/events.ts | 6 +- .../.github/copilot-instructions.md | 135 +++++++++++++++++- .../Challenge-02-NYCApp/src/data/events.ts | 6 +- 7 files changed, 161 insertions(+), 24 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md index ba1c957141..ec736a1d70 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md @@ -1,6 +1,5 @@ +# Copilot Instructions (GLOBAL) -# ✅ Optimized Global Instructions - -- Write clean, readable code +- Write clean, readable, maintainable code - Prefer clarity over complexity -- Return structured JSON responses +- Return structured JSON responses \ No newline at end of file diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md index c7d7ed7505..812179cc0f 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md @@ -1,9 +1,11 @@ - --- applyTo: "src/routes/**/*.ts" --- # API Rules -- Use REST conventions + +- Use RESTful conventions - Return structured JSON responses -- Validate inputs +- Include a `count` field for list responses +- Validate request inputs +- Use appropriate HTTP status codes \ No newline at end of file diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md index 6b03b8fd85..ac754d838a 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md @@ -1,9 +1,11 @@ - --- applyTo: "src/routes/events.ts" --- # Events Rules -- price === 0 -- within next 7 days -- sort by date ascending + +- Only return events where `price === 0` +- Only include events happening within the next 7 days +- Exclude past events +- Sort results by date ascending +- Ensure each event has name, date, and location \ No newline at end of file diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md index 7fdc0c2946..6a274076cf 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md @@ -1,9 +1,12 @@ - --- name: free-events-endpoint +description: Use when creating or updating a free events endpoint --- -Filter events: -1. price === 0 -2. next 7 days -3. sort ascending +# Free Events Endpoint + +1. Filter events where `price === 0` +2. Filter events within the next 7 days +3. Exclude invalid or incomplete entries +4. Sort results by date ascending +5. Return `{ count, events }` \ No newline at end of file diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts index 32484a7ad7..44040e6bd4 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts @@ -1,7 +1,7 @@ export const events = [ - { name: 'Central Park Yoga', date: '2026-06-20', price: 0 }, - { name: 'Brooklyn Flea Market Walk', date: '2026-06-22', price: 0 }, - { name: 'Rooftop Movie Night', date: '2026-06-25', price: 15 }, + { name: 'Central Park Yoga', date: '2026-06-30', price: 0 }, + { name: 'Brooklyn Flea Market Walk', date: '2026-07-01', price: 0 }, + { name: 'Rooftop Movie Night', date: '2026-07-02', price: 15 }, { name: 'Jazz in Washington Square Park', date: '2026-07-10', price: 0 } ]; diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md index d59eccf55c..e2469755d4 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md @@ -1,4 +1,4 @@ - +<!-- # Copilot Instructions (INTENTIONALLY BLOATED) - Always validate inputs @@ -13,4 +13,135 @@ - Neighborhoods must include transit and vibe - Events must include price and date filtering -# TOO BIG ON PURPOSE +# TOO BIG ON PURPOSE --> +# Copilot Instructions (INTENTIONALLY BLOATED) + +## General Engineering Rules +- Always write clean, maintainable, scalable, and production-ready code +- Always validate all inputs at every layer of the application +- Always handle errors gracefully with meaningful error messages +- Always use descriptive variable and function naming +- Always include comments explaining business logic +- Avoid deeply nested logic whenever possible +- Prefer modular and reusable components +- Ensure all code is optimized for performance +- Avoid unnecessary computations and loops +- Minimize memory usage and API calls + +## API Design Rules +- Use RESTful conventions for all endpoints +- Ensure consistent naming for endpoints (plural nouns) +- Always return JSON responses +- Always include HTTP status codes +- Validate all query parameters and request bodies +- Use middleware for validation and error handling +- Return responses in the format: + { + "count": number, + "data": [] + } +- Never expose internal implementation details in responses + +## Frontend Rules (NOT RELEVANT BUT INCLUDED) +- Use React functional components only +- Prefer hooks over class components +- Use useEffect and useState appropriately +- Ensure accessibility (ARIA labels, keyboard navigation) +- Optimize rendering performance +- Use responsive design principles +- Avoid unnecessary re-renders +- Ensure clean UI/UX design patterns + +## Data Modeling Rules +- Normalize JSON structures +- Avoid duplicate data +- Use consistent field naming across all datasets +- Prefer arrays of objects for collections +- Always use ISO date formats (YYYY-MM-DD) +- Avoid null values when possible +- Ensure backward compatibility of schema changes + +## Restaurant Domain Rules (NOT NEEDED FOR EVENTS) +- Restaurants must include: + - name + - borough + - cuisine + - rating + - priceLevel +- Include vegetarian-friendly indicators +- Include neighborhood information +- Include vibe descriptions (e.g., cozy, lively, romantic) +- Include wait time estimates for popular locations + +## Neighborhood Domain Rules (NOT NEEDED FOR EVENTS) +- Neighborhoods must include: + - borough + - vibe + - transit options + - average rent tier + - bestFor categories +- Include walkability information +- Include proximity to parks, restaurants, and nightlife +- Include safety considerations +- Use engaging and descriptive language + +## Events Domain Rules (ACTUALLY RELEVANT) +- Events must include: + - name + - date + - location + - borough + - price +- Free events must have price === 0 +- Events must be filtered based on date when required +- Events must be sorted by date ascending +- Exclude past events +- Ensure event data is complete and valid + +## Testing Rules (NOT USED IN THIS TASK) +- Write unit tests for business logic +- Write integration tests for endpoints +- Mock dependencies when necessary +- Ensure proper test coverage (at least 80%) +- Test edge cases thoroughly +- Validate error handling paths + +## Logging and Monitoring Rules +- Log all important actions +- Log errors with stack traces (but not in responses) +- Ensure logs are structured +- Include timestamps in logs +- Avoid logging sensitive data + +## Security Rules +- Validate all inputs to prevent injection attacks +- Sanitize user input +- Avoid exposing secrets or keys +- Use environment variables for configuration +- Follow principle of least privilege + +## NYC Content & Tone Rules +- Keep examples fun and NYC-specific +- Reference locations like Central Park, Brooklyn, SoHo, Williamsburg +- Use relatable, local descriptions +- Avoid generic or bland wording +- Make the application feel like it’s built for a real NYC resident + +## Performance Optimization Rules +- Optimize loops and filtering logic +- Avoid redundant computations +- Cache results where possible +- Minimize memory footprint +- Reduce unnecessary API calls + +--- + +# ⚠️ THIS FILE IS INTENTIONALLY OVERLOADED + +It includes: +- ✅ relevant rules (events) +- ❌ irrelevant domains (restaurants, neighborhoods) +- ❌ unrelated layers (frontend, security, logging, testing) + +👉 Students should REDUCE this drastically. +`` \ No newline at end of file diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts index 32484a7ad7..44040e6bd4 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts @@ -1,7 +1,7 @@ export const events = [ - { name: 'Central Park Yoga', date: '2026-06-20', price: 0 }, - { name: 'Brooklyn Flea Market Walk', date: '2026-06-22', price: 0 }, - { name: 'Rooftop Movie Night', date: '2026-06-25', price: 15 }, + { name: 'Central Park Yoga', date: '2026-06-30', price: 0 }, + { name: 'Brooklyn Flea Market Walk', date: '2026-07-01', price: 0 }, + { name: 'Rooftop Movie Night', date: '2026-07-02', price: 15 }, { name: 'Jazz in Washington Square Park', date: '2026-07-10', price: 0 } ]; From cd5243111500296bee271b117c7719b032cffd8e Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 1 Jul 2026 15:46:14 -0700 Subject: [PATCH 25/48] Create sales.csv --- .../Student/Resources/Challenge06/data/sales.csv | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge06/data/sales.csv diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge06/data/sales.csv b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge06/data/sales.csv new file mode 100644 index 0000000000..def8a67565 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge06/data/sales.csv @@ -0,0 +1,16 @@ +date,category,amount,note +2026-01-03,Electronics,199.99, +2026-01-05,Books,12.50, +2026-01-06,books,9.99,"reorder, please" +2026-01-07,Books ,0.10, +2026-01-08, BOOKS,0.20, +2026-01-09,Electronics,50.00, +2026-01-10,"Toys, Games",24.99, +2026-01-11,Food,5.25, +2026-01-12,food, 5.75, +2026-01-13, FOOD ,4.00,"bulk order +spanning two lines" +2026-01-14,<script>alert('xss')</script>,13.00, +2026-01-15,Electronics,N/A, +2026-01-16,,7.00, +2026-01-17,Books,0.20, From 97f73c381c699c38135eef4b51abae27c8d7a112 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 1 Jul 2026 15:56:03 -0700 Subject: [PATCH 26/48] Adding devcontainer files --- .../devcontainer.json | 32 +++++++++++++++++++ .../Resources/.devcontainer/devcontainer.json | 30 +++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 .devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json diff --git a/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json b/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json new file mode 100644 index 0000000000..cb9364b973 --- /dev/null +++ b/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json @@ -0,0 +1,32 @@ +{ + "name": "xxx-GitHubCopilotCostOptimization", + "image": "mcr.microsoft.com/devcontainers/universal:2", + "workspaceFolder": "/workspace/xxx-GitHubCopilotCostOptimization/Student/Resources", + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached", + "hostRequirements": { + "cpus": 2 + }, + "features": {}, + "customizations": { + "vscode": { + "extensions": [ + "github.copilot", + "github.copilot-chat", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] + }, + "codespaces": { + "openFiles": [ + "xxx-GitHubCopilotCostOptimization/Student/Resources/README.md" + ] + } + }, + "forwardPorts": [3000], + "portsAttributes": { + "3000": { + "label": "CityScout NYC App", + "onAutoForward": "notify" + } + } +} diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json b/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..575863c0a1 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json @@ -0,0 +1,30 @@ +{ + "name": "xxx-GitHubCopilotCostOptimization", + "image": "mcr.microsoft.com/devcontainers/universal:2", + "hostRequirements": { + "cpus": 2 + }, + "features": {}, + "customizations": { + "vscode": { + "extensions": [ + "github.copilot", + "github.copilot-chat", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] + }, + "codespaces": { + "openFiles": [ + "README.md" + ] + } + }, + "forwardPorts": [3000], + "portsAttributes": { + "3000": { + "label": "CityScout NYC App", + "onAutoForward": "notify" + } + } +} From a9989300572568bdef431edf6297db8bdda1423f Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 1 Jul 2026 16:26:24 -0700 Subject: [PATCH 27/48] Updated to install spec kit --- .../xxx-GitHubCopilotCostOptimization/devcontainer.json | 2 ++ .../Student/Resources/.devcontainer/devcontainer.json | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json b/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json index cb9364b973..b691f9dc50 100644 --- a/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json +++ b/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json @@ -22,6 +22,8 @@ ] } }, + "postCreateCommand": "curl -LsSf https://astral.sh/uv/install.sh | sh && ~/.local/bin/uv tool install specify-cli --from git+https://github.com/github/spec-kit.git", + "forwardPorts": [3000], "portsAttributes": { "3000": { diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json b/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json index 575863c0a1..f6d578d9d8 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json @@ -20,6 +20,8 @@ ] } }, + "postCreateCommand": "curl -LsSf https://astral.sh/uv/install.sh | sh && ~/.local/bin/uv tool install specify-cli --from git+https://github.com/github/spec-kit.git", + "forwardPorts": [3000], "portsAttributes": { "3000": { From 7948dddcf1e4c2fd01519c9add0147b24d602de8 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Wed, 1 Jul 2026 16:36:00 -0700 Subject: [PATCH 28/48] updated to smaller container --- .../xxx-GitHubCopilotCostOptimization/devcontainer.json | 6 ++++-- .../Student/Resources/.devcontainer/devcontainer.json | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json b/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json index b691f9dc50..310bc826a5 100644 --- a/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json +++ b/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json @@ -1,12 +1,14 @@ { "name": "xxx-GitHubCopilotCostOptimization", - "image": "mcr.microsoft.com/devcontainers/universal:2", + "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", "workspaceFolder": "/workspace/xxx-GitHubCopilotCostOptimization/Student/Resources", "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached", "hostRequirements": { "cpus": 2 }, - "features": {}, + "features": { + "ghcr.io/devcontainers/features/python:1": { "version": "3.12" } + }, "customizations": { "vscode": { "extensions": [ diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json b/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json index f6d578d9d8..43ee4df62b 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json @@ -1,10 +1,12 @@ { "name": "xxx-GitHubCopilotCostOptimization", - "image": "mcr.microsoft.com/devcontainers/universal:2", + "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", "hostRequirements": { "cpus": 2 }, - "features": {}, + "features": { + "ghcr.io/devcontainers/features/python:1": { "version": "3.12" } + }, "customizations": { "vscode": { "extensions": [ From 77fcc99c44d03acc1663528a7d27f7dabd754d6e Mon Sep 17 00:00:00 2001 From: ana-codes-1 <ana-codes-1@users.noreply.github.com> Date: Thu, 9 Jul 2026 10:52:14 -0400 Subject: [PATCH 29/48] Add open-ended pickleball planning task to Challenge 03 Adds Part 3 (judge quality on an open-ended planning task) after the car wash example, with a scoring rubric and cost tie-in. Renumbers the compare and classify sections to Parts 4 and 5. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Student/Challenge-03.md | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md index 1618e648d0..2f237acfd6 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md @@ -98,7 +98,50 @@ The trap: you could burn several low-cost attempts, pass the cost of one premium --- -## Part 3 — Compare Results & Decide +## Part 3 — An Open-Ended Task (judge the *quality*, not a right answer) + +Parts 1 and 2 each had a checkable answer. **Most real work doesn't.** When you plan a feature, design a schema, or scope a project with Copilot, there's no answer key — *you* have to judge whether the output is any good. That judgment is the skill this part builds, and it's where model choice matters most. + +Give **both** models this exact prompt: + +``` +I want to build a pickleball app. Produce an implementation plan. +First, ask me any clarifying questions you need. Then identify the +top 5 risks or hidden complexities that could derail this project, +and highlight them in the plan. +``` + +Notice the prompt is **deliberately vague** ("a pickleball app" — to do *what*?). That's on purpose: a strong model should *notice the gap and ask* before it plans. The risk question then forces the model to actually **think**, not just fill in a template. + +### Record & Score + +There's no correct answer, so score each response against this rubric instead: + +| Criterion | Base model | Premium model | +|---|---|---| +| Asked clarifying questions *before* planning? (how many, how sharp) | ? | ? | +| Top-5 risks: generic ("scope creep, budget") or genuinely insightful? | ? | ? | +| Plan specific to *pickleball* — or a generic "any app" template? | ? | ? | +| Would you trust it enough to start building? | ? | ? | +| Total tokens | ? | ? | + +### What to notice + +The base model tends to **charge straight ahead**: it assumes what the app is, produces a plausible-but-generic plan, and lists generic risks (budget, timeline, scope creep). It rarely stops to ask what you're actually building. + +The premium model is more likely to **ask sharp clarifying questions first** (court booking? player matchmaking/ranking? score tracking? league scheduling? who are the users?) and to surface **deeper, domain-specific risks** — double-booking / concurrency on court reservations, ranking fairness, real-time score sync, geolocation privacy, no-show and cancellation handling. Those are exactly the risks that quietly derail a project. + +> **The cost tie-in:** the premium plan costs more tokens up front. But a shallow plan isn't cheap — it's **deferred cost.** Every risk the base model *didn't* flag becomes rework, a rewrite, or a bug you pay for at execution time. On open-ended, high-leverage work, paying more for *deeper thinking* is usually the economical choice — the mirror image of Part 1, where paying more bought you nothing. + +### Questions to Answer + +1. Which model's plan would you actually trust enough to start building from — and why? +2. Did the extra tokens the premium model spent buy you real value here (unlike Part 1)? What specifically? +3. This task has no "right answer." How did you decide which output was *better*? What made the difference? + +--- + +## Part 4 — Compare Results & Decide Combine your measurements into one table: @@ -106,6 +149,7 @@ Combine your measurements into one table: |------|----------------|--------------|-------------------|-----------------|-----------------------------| | Part 1 (easy) | ? | ? | ? | ? | ? | | Part 2 (hard) | ? | ? | ? | ? | ? | +| Part 3 (open-ended) | judge quality | ? | judge quality | ? | ? | ### Questions to Answer @@ -116,7 +160,7 @@ Combine your measurements into one table: --- -## Part 4 — Classify Your Own Tasks +## Part 5 — Classify Your Own Tasks The skill this challenge builds is *prediction*: knowing which tier a task needs **before** you spend anything. @@ -160,6 +204,7 @@ To complete this challenge successfully, you should be able to: - Record outcome (correct/incorrect) and token usage for all four runs - Show that on the easy task the base model was correct **and** used fewer tokens - Show that on the hard task the base model was confidently wrong while the premium model was correct +- On the open-ended planning task, judge each model's *quality* against the rubric (clarifying questions, depth of the top-5 risks, specificity, trust-to-start) and explain which you'd build from - Reason about how many base-model retries it would take to cost more than one premium call — and why retries can't fix a reasoning-ceiling task - Classify two of your own real tasks by tier and verify your prediction - (Optional) Demonstrate a token reduction by adding an output constraint to a verbose task From 0f3ae9d789b62d4c0c1fcf9187bcc723f0231f37 Mon Sep 17 00:00:00 2001 From: Devanshi <devanshi.thakar123@gmail.com> Date: Fri, 10 Jul 2026 11:04:48 -0400 Subject: [PATCH 30/48] restructured the Challenge-02.md file with latest instructions for the students and changed the coach guidance accordingly --- .../Challenge-02-NYCApp-Solutions/README.md | 2 +- .../Student/Challenge-02.md | 107 ++++++++++++++---- 2 files changed, 85 insertions(+), 24 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md index edfd842ee8..53366e4c00 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md @@ -1,5 +1,5 @@ -# CityScout NYC - ✅ Challenge 1 Complete Solution (v2) +# CityScout NYC - ✅ Challenge 2 Complete Solution (v2) This is the fully optimized version showing: - Reduced global instructions ✅ diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md index 62780f7f4c..081a3aaa58 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md @@ -1,52 +1,113 @@ -# Challenge 02 - Context Engineering +# Challenge 02 - Context Engineering (NYC App) [< Previous Challenge](./Challenge-01.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-03.md) ## Introduction -Every token sent to GitHub Copilot has a cost. Context that persists across every interaction—like global `.github/copilot-instructions.md` files—creates recurring costs that compound quickly. Meanwhile, broad workspace references like `#Codebase` pull in unnecessary files, adding tokens you don't need. +In this challenge, you will optimize Copilot context using a real code task in the NYC starter app under Resources/Challenge-02-NYCApp. -In this challenge, you'll learn to engineer your context precisely. You'll audit an over-stuffed global instructions file, restructure it into scoped path-specific files, and replace broad references with pinned attachments. The goal: reduce the base cost of every Copilot interaction while maintaining quality. +The app intentionally includes an oversized global `.github/copilot-instructions.md` file and multiple routes (`events`, `restaurants`, `neighborhoods`) so you can compare broad context (`#Codebase`) against precise, task-focused attachments. + +Every token sent to GitHub Copilot has a cost. Context that persists across interactions, such as global instruction files or broad workspace references, can increase recurring spend by adding tokens that are not needed for the current task. + +You will audit the over-stuffed global instructions file, restructure it into scoped path-specific files, and replace broad references with pinned attachments to reduce the base cost of each Copilot interaction while maintaining output quality. ## Description -The starter codebase includes an intentionally bloated `.github/copilot-instructions.md` file that loads on every GitHub Copilot interaction. Your challenge is to reduce the base cost of every interaction through context optimization. +Use the project in: + +`Resources/Challenge-02-NYCApp` + +### Part 1 - Scope Instructions + +1. Audit `.github/copilot-instructions.md` and identify what is: + - universally useful + - specific to events + - irrelevant for this task (for example, restaurants/neighborhoods/frontend/testing rules) +2. Shrink the global file to only truly global guidance. +3. Create scoped instruction files under `.github/instructions/` for rules that should apply only to specific paths/tasks. For example, create an `api.instructions.md` file and an `events.instructions.md` file. +4. Keep the events-specific logic discoverable for work in `src/routes/events.ts`. +5. Create a reusable Copilot skill under `.github/skills/free-events-endpoint/SKILL.md` that captures the pattern for implementing a free events endpoint. This skill should only load when explicitly invoked, making it a conditional cost rather than a recurring one. + +### Part 2 - Implement the Baseline Route Task + +Implement `GET /events/free-this-week` in `src/routes/events.ts` with this behavior: + +- include events where `price === 0` +- include only events within the next 7 days +- sort ascending by date +- return JSON in the shape `{ count, events }` + +Important: + +- modify `src/routes/events.ts` +- do not modify `src/routes/restaurants.ts` +- do not modify `src/routes/neighborhoods.ts` + +### Part 3 - Attachment Precision and Token Usage Check + +In the GitHub Copilot Chat interface, run this exact query twice and compare results: + +"What data or features does this application support?" + +Run it twice and record the token usage each time: + +1. Without scoped files (broad context, such as `#Codebase`) +2. With scoped files pinned (only task-relevant files, for example: `src/routes/events.ts`, `src/data/events.ts`, and relevant instruction files) + +Capture both token counts from the Copilot Chat usage details/output, compare answer quality, and calculate the difference. + +For each run, record context window stats in this format: + +- Used tokens / Total context window tokens +- Context window utilization percentage + +Example format: -### Instruction Scoping +- Run A (broad): 8,200 / 32,000 (25.6%) +- Run B (scoped): 2,100 / 32,000 (6.6%) -Audit the global instructions file and restructure it for efficiency: +Then compute: -- Identify which rules apply universally vs. only to specific languages or directories -- Minimize the global file by moving scoped rules to appropriate locations -- Consider converting task-specific patterns to GitHub Copilot Skills that activate conditionally -- Discover how language-specific and path-specific instruction files work +- Used-token delta (A - B) +- Utilization delta in percentage points -### Attachment Precision +Use this table to record your measurements: -Experiment with workspace references to understand their token cost: +| Run | Context Strategy | Query | Used Tokens | Total Context Window Tokens | Utilization % | Notes | +|-----|------------------|-------|-------------|-----------------------------|---------------|-------| +| A | Broad (`#Codebase` or equivalent) | What data or features does this application support? | | | | | +| B | Scoped pinned files | What data or features does this application support? | | | | | -- Compare using `#Codebase` vs. pinning specific files for the same coding task -- Measure the token difference between broad and precise attachment strategies -- Verify that output quality remains equivalent with more precise attachments +| Comparison Metric | Value | +|-------------------|-------| +| Used-token delta (A - B) | | +| Utilization delta percentage points (A - B) | | -Use the baseline coding task from Challenge 00 to measure the impact of your optimizations. Compare credit consumption before and after restructuring to demonstrate measurable savings. ## Success Criteria To complete this challenge successfully, you should be able to: -- Demonstrate that your restructured global `.github/copilot-instructions.md` is significantly smaller than the original -- Show path-specific or language-specific instruction files you created with rules moved from the global file -- Verify that at least one task-specific pattern has been converted to a GitHub Copilot Skill -- Show token count comparison between using `#Codebase` vs. pinned file attachments for a specific task -- Demonstrate measurable credit reduction on the baseline coding task -- Verify that code quality remained equivalent after optimization +- Show that `.github/copilot-instructions.md` is significantly smaller than the original +- Show scoped instruction files created in `.github/instructions/` +- Show a reusable skill created at `.github/skills/free-events-endpoint/SKILL.md` +- Demonstrate a correct `/events/free-this-week` implementation in `src/routes/events.ts` +- Demonstrate that `src/routes/restaurants.ts` and `src/routes/neighborhoods.ts` remained unchanged +- Show token comparison between `#Codebase` and pinned attachments for the same task +- Show Part 3 token and context-window comparison for the query "What data or features does this application support?" in Copilot Chat: + - without scoped files + - with scoped pinned files + - with documented context window stats (used / total) + - with documented utilization percentage for both runs + - with documented token and utilization deltas +- Show measurable credit reduction while preserving output quality ## Learning Resources - [GitHub Copilot Instructions Documentation](https://docs.github.com/en/copilot/customizing-copilot/adding-custom-instructions-for-github-copilot) +- [GitHub Copilot Prompt Files and Attachments](https://docs.github.com/en/copilot/using-github-copilot/asking-github-copilot-questions-in-your-ide#reference-files-in-your-prompts) - [GitHub Copilot Skills Overview](https://docs.github.com/en/copilot/using-github-copilot/using-github-copilot-skills) -- [Understanding Context Windows in Large Language Models](https://www.anthropic.com/index/prompting-long-context) ## Tips From afb10ec9e88f7baa301ab31f24622a6484fab893 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Fri, 10 Jul 2026 08:22:13 -0700 Subject: [PATCH 31/48] Update Challenge-04.md --- xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md index ec2efefc17..fc18157d9b 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md @@ -4,7 +4,7 @@ ## Introduction -Every MCP tool you enable adds token overhead to every agent step. Each tool's name, description, and parameter schema are advertised to the model on every request—even if the tool is never invoked. A session with many unused tools burns credits before you've written a line of code. +Every MCP tool and Skill you enable adds token overhead to every agent step. Each tool's name, description, and parameter schema are advertised to the model on every request—even if the tool is never invoked. A session with many unused tools burns credits before you've written a line of code. Meanwhile, changing configuration mid-session can trigger cache invalidation, forcing expensive cold restarts where previously cached context must be reprocessed. @@ -14,15 +14,15 @@ In this challenge, you'll measure the real cost of tool sprawl and observe how s This challenge has two parts: measuring MCP tool overhead and observing cache invalidation behavior. -### Part 1: Measure MCP Tool Overhead +### Part 1: Measure MCP Tool and Skills Overhead Use GitHub Copilot to scan/find something in the `microsoft/TypeScript` repository and report back. If you don't have MCP servers enabled already, try the GitHub MCP server with all its tools. Complete the task with all tools enabled and record your credit spend. -Next, identify which MCP tools were actually used. +Next, identify which MCP tools and skills were actually used. -Disable the unused tools, repeat the scan, and measure the credit difference. Each unused tool adds token overhead on every agent step because its schema is included in the system prompt. +Disable the unused tools and skills, repeat the scan, and measure the credit difference. Each unused tool adds token overhead on every agent step because its schema is included in the system prompt. ### Part 2: Observe Cache Invalidation From ccfe0e5dc17ff672cf854c0b6ae0a159a6a551e5 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Fri, 10 Jul 2026 08:59:38 -0700 Subject: [PATCH 32/48] Update Challenge-05.md --- .../Student/Challenge-05.md | 84 ++++++++++++++----- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index bd4e67d381..1908931295 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -2,40 +2,81 @@ [< Previous Challenge](./Challenge-04.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-06.md) +## Pre-requisites + +- Complete Challenge 02 (Context Engineering) — you will extend the CityScout NYC App from that challenge +- Complete Challenge 04 (Session Configuration: Tools + Cache) + ## Introduction -Context windows grow with every interaction. As your session accumulates messages, attachments, and generated code, the context window fills. When utilization gets too high, quality degrades—responses become less accurate, the model "forgets" earlier decisions, and credits burn faster as you pay to transmit bloated context. +Context windows grow with every interaction. As a session accumulates messages, attachments, and generated code, the model has more history to process each turn. -In this challenge, you'll learn when and how to use `/compact` (the steering wheel) vs. `/clear` (the reset button). The biggest avoidable cost isn't running `/compact` too often—it's running it too late, after context rot has already degraded quality and forced expensive recovery loops. +When context grows too large, quality often drops: missed requirements, repeated questions, inconsistent edits, and higher credit spend. In this challenge, you will compare proactive `/compact` against unmanaged context growth, then practice when `/clear` is the correct recovery move. ## Description -Complete a multi-turn coding task designed to intentionally grow your context window. You'll compare two approaches: proactive compaction vs. reactive recovery. +You will extend the **CityScout NYC App** (from Challenge 02) with four new features, then compare two session strategies side-by-side. The features deliberately span all three routes and force topic switching—exactly the conditions that grow context fast. + +### The Task: CityScout Feature Sprint + +Using the NYC App you worked with in Challenge 02 (in `Resources/Challenge-02-NYCApp`), implement these four features in order: + +- **Feature 1 – Restaurant Filtering:** Add query-parameter support to `GET /restaurants` so callers can filter by `borough` and/or `cuisine` (e.g., `/restaurants?borough=Brooklyn&cuisine=Mexican`). Return the full list when no filters are provided. +- **Feature 2 – Neighborhood Detail with Restaurants:** Add `GET /neighborhoods/:name` that returns the matching neighborhood object plus an embedded array of restaurants in that neighborhood (a cross-file join between `neighborhoods.ts` and `restaurants.ts` data). +- **Feature 3 – Pagination (cross-cutting):** Add `?page=N&limit=N` support to all three list endpoints (`/events/free-this-week`, `/restaurants`, `/neighborhoods`). Default to page 1, limit 10. Return `{ page, limit, total, data }`. +- **Feature 4 – Input Validation & Error Handling:** Add proper `400 Bad Request` responses for invalid query params and `404 Not Found` for missing resources across all routes. + +These four features touch multiple files, require cross-file references, and create natural breakpoints between each feature—ideal for testing context management strategies. + +### Run A – Unmanaged Context Growth + +Implement all four features in a single session without ever using `/compact`: + +- Let context accumulate naturally as you move from feature to feature +- Do not start new sessions between features +- Track credit usage after each feature completes +- Watch for quality degradation signals as context grows: + - Copilot forgets earlier requirements (e.g., pagination format differs between routes) + - Contradictory suggestions (e.g., different error shapes in different routes) + - Repeated clarifying questions you already answered + - Increased rework or manual corrections -### Context Rot Observation +Record a brief evidence note after each feature: what worked, what degraded. -Start a coding task that involves multiple related features or refactors. Intentionally let the context window grow by adding numerous file attachments, requesting verbose explanations, and allowing the conversation to accumulate without intervention. +### Run B – Proactive Context Management -Monitor context window utilization (visible in VS Code status bar or Output panel) and observe what happens as it fills. Look for quality degradation signals like inconsistencies, forgotten requirements, or repeated questions. Record credits consumed and note any incorrect outputs or rework needed. +Implement the same four features, but actively manage context throughout. You choose your own strategy: -### Proactive Compaction +- `/compact` to summarize and continue in the same session +- `/clear` to wipe and restart with a fresh prompt +- Start a new session (`/new`) at any breakpoint you choose -Restart the same multi-turn task using proactive `/compact` at natural breakpoints (after completing a feature, before switching topics). Keep the context window lean throughout and monitor how compaction summarizes previous work while preserving state. Compare credits consumed and output quality vs. the unmanaged approach. +The goal is to keep context lean and credit spend low. Track total credits across the entire sprint (including any new sessions you start) and compare with Run A. Document which context management actions you took and why. -### Emergency Reset +### Run C – Emergency Reset (`/clear`) -Demonstrate when `/clear` is appropriate by starting a task where you realize mid-way that your approach is fundamentally wrong. Use `/clear` to wipe context and start fresh with a corrected approach. Understand the cold cache penalty from `/clear` vs. preserved cache with `/compact`. +This run uses a **separate, short task** (not the full feature sprint): +- Start a new session and ask Copilot to refactor the restaurants route into a class-based controller pattern +- After a few turns, "realize" the approach is wrong (perhaps your team uses functional handlers, or the refactor conflicts with your pagination design from Runs A/B) +- Attempt one correction prompt to see if the session can recover +- When incremental correction is clearly more expensive than starting over, use `/clear` +- Restart with a corrected approach and finish the refactor +- Record what changed after reset: + - What useful context was lost (file contents, decisions, naming conventions) + - What had to be re-established before you could continue + - Credit and time cost of the cold restart vs. what you spent trying to fix the session ## Success Criteria To complete this challenge successfully, you should be able to: -- Demonstrate observable quality degradation when context window grows too large -- Show credit cost comparison between unmanaged context growth and proactive compaction approaches -- Verify that proactive `/compact` maintained output quality throughout the multi-turn task -- Demonstrate appropriate use of `/clear` when the context becomes fundamentally misaligned -- Explain the difference in cache impact between `/compact` (preserves cache) and `/clear` (cold restart) +- Demonstrate at least two concrete quality degradation signals from Run A +- Show a side-by-side credit comparison between Run A and Run B for the same four features +- Verify that your Run B context management strategy reduced total credit spend compared to Run A +- Demonstrate a valid scenario where `/clear` was the correct decision in Run C +- Explain the trade-offs between `/compact`, `/clear`, and starting a new session +- Show a concise evidence log for all three runs (context management actions taken, credits per feature, total credits) ## Learning Resources @@ -45,9 +86,10 @@ To complete this challenge successfully, you should be able to: ## Tips -- Context rot starts when the window gets too full—don't wait until the last moment -- `/compact` is the steering wheel (summarize, preserve state)—use it proactively -- `/clear` is the reset button (wipe everything)—use it when direction changes -- Natural breakpoints: feature complete, tests passing, architecture decision made -- The cost isn't running `/compact`—it's NOT running `/compact` until quality has already degraded -- Compact before you feel the pain, not after +- Do not optimize for speed first; optimize for clean credit comparisons between runs +- Keep the four features identical between Run A and Run B so the credit comparison is meaningful +- Record credits after each feature, not just at the end — this shows where costs accelerate +- There is no single "right" strategy for Run B; `/compact`, `/clear`, and `/new` all have trade-offs +- `/compact` preserves some context continuity but costs tokens to summarize +- `/clear` and `/new` give you a cold start — cheap per-turn but you re-establish context from scratch +- The best strategy often mixes approaches depending on how much earlier context the next feature needs From 8e59922c01872abb6af0b04bc2e6be2ecbb63d67 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Fri, 10 Jul 2026 09:00:46 -0700 Subject: [PATCH 33/48] Update Challenge-05.md --- xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index 1908931295..cd49ce036f 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -11,7 +11,7 @@ Context windows grow with every interaction. As a session accumulates messages, attachments, and generated code, the model has more history to process each turn. -When context grows too large, quality often drops: missed requirements, repeated questions, inconsistent edits, and higher credit spend. In this challenge, you will compare proactive `/compact` against unmanaged context growth, then practice when `/clear` is the correct recovery move. +When context grows too large, quality often drops: missed requirements, repeated questions, inconsistent edits, and higher credit spend. In this challenge, you will compare proactive proactive context management to not performing these actions. ## Description From 273f4fbba6f2461dff863e7b12058177dac27fd5 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Fri, 10 Jul 2026 09:01:33 -0700 Subject: [PATCH 34/48] Update Challenge-05.md --- xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index cd49ce036f..b15ed6d3df 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -26,7 +26,7 @@ Using the NYC App you worked with in Challenge 02 (in `Resources/Challenge-02-NY - **Feature 3 – Pagination (cross-cutting):** Add `?page=N&limit=N` support to all three list endpoints (`/events/free-this-week`, `/restaurants`, `/neighborhoods`). Default to page 1, limit 10. Return `{ page, limit, total, data }`. - **Feature 4 – Input Validation & Error Handling:** Add proper `400 Bad Request` responses for invalid query params and `404 Not Found` for missing resources across all routes. -These four features touch multiple files, require cross-file references, and create natural breakpoints between each feature—ideal for testing context management strategies. +These four features touch multiple files, require cross-file references, and create natural breakpoints between each feature—ideal for testing context management strategies. We recommend not committing these files to make it easier to revert. ### Run A – Unmanaged Context Growth From c4ccad60470fc37000ef6b13f0f39bcac7f79a6b Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Fri, 10 Jul 2026 10:04:54 -0700 Subject: [PATCH 35/48] Update Challenge-05.md --- .../Student/Challenge-05.md | 21 +++---------------- 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md index b15ed6d3df..7232f3c8fd 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -11,11 +11,11 @@ Context windows grow with every interaction. As a session accumulates messages, attachments, and generated code, the model has more history to process each turn. -When context grows too large, quality often drops: missed requirements, repeated questions, inconsistent edits, and higher credit spend. In this challenge, you will compare proactive proactive context management to not performing these actions. +When context grows too large, quality often drops: missed requirements, repeated questions, inconsistent edits, and higher credit spend. In this challenge, you will compare unmanaged context growth against proactive context management and measure the credit difference. ## Description -You will extend the **CityScout NYC App** (from Challenge 02) with four new features, then compare two session strategies side-by-side. The features deliberately span all three routes and force topic switching—exactly the conditions that grow context fast. +You will extend the **CityScout NYC App** (from Challenge 02) with four new features, then compare two session strategies side-by-side: one where you let context grow unchecked, and one where you actively manage it. The features deliberately span all three routes and force topic switching—exactly the conditions that grow context fast. ### The Task: CityScout Feature Sprint @@ -53,20 +53,6 @@ Implement the same four features, but actively manage context throughout. You ch The goal is to keep context lean and credit spend low. Track total credits across the entire sprint (including any new sessions you start) and compare with Run A. Document which context management actions you took and why. -### Run C – Emergency Reset (`/clear`) - -This run uses a **separate, short task** (not the full feature sprint): - -- Start a new session and ask Copilot to refactor the restaurants route into a class-based controller pattern -- After a few turns, "realize" the approach is wrong (perhaps your team uses functional handlers, or the refactor conflicts with your pagination design from Runs A/B) -- Attempt one correction prompt to see if the session can recover -- When incremental correction is clearly more expensive than starting over, use `/clear` -- Restart with a corrected approach and finish the refactor -- Record what changed after reset: - - What useful context was lost (file contents, decisions, naming conventions) - - What had to be re-established before you could continue - - Credit and time cost of the cold restart vs. what you spent trying to fix the session - ## Success Criteria To complete this challenge successfully, you should be able to: @@ -74,9 +60,8 @@ To complete this challenge successfully, you should be able to: - Demonstrate at least two concrete quality degradation signals from Run A - Show a side-by-side credit comparison between Run A and Run B for the same four features - Verify that your Run B context management strategy reduced total credit spend compared to Run A -- Demonstrate a valid scenario where `/clear` was the correct decision in Run C - Explain the trade-offs between `/compact`, `/clear`, and starting a new session -- Show a concise evidence log for all three runs (context management actions taken, credits per feature, total credits) +- Show a concise evidence log for both runs (context management actions taken, credits per feature, total credits) ## Learning Resources From 0b5268b3d1b6ac0a7efb7b2d518fc4b153b5b05f Mon Sep 17 00:00:00 2001 From: ana-codes-1 <ana-codes-1@users.noreply.github.com> Date: Fri, 24 Jul 2026 11:01:39 -0400 Subject: [PATCH 36/48] Replace car wash hard task with open-ended pickleball planning task Removes the deterministic car wash task and promotes the open-ended pickleball planning task into Part 2. Rewords the intro, no-retry rule, compare/classify sections, success criteria, and reflection questions to fit a checkable + open-ended task pair instead of easy/hard. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Student/Challenge-03.md | 80 +++++-------------- 1 file changed, 19 insertions(+), 61 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md index 2f237acfd6..e40e1e9780 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md @@ -8,15 +8,15 @@ Not every task needs the most powerful model. Under usage-based billing, cost is > **Total cost = token rate × tokens × attempts** -That last term — *attempts* — is the one people forget. A **base model** that answers a simple task correctly in a few tokens is a bargain. But that same base model, set loose on a task it cannot actually reason through, will hand you a **confident, wrong answer**. Now you are paying again (and again) to notice it is wrong and redo the work. The model that looked lower-cost per request just became the costliest one. +That last term — *attempts* — is the one people forget. A **base model** that answers a simple task correctly in a few tokens is a bargain. But set that same base model on work that needs real judgment and it will hand you a **plausible-looking answer that's shallow or flat-out wrong** — and you won't always catch it right away. Now you are paying again (and again) to notice the gap and redo the work. The model that looked lower-cost per request just became the costliest one. -In this challenge you will run the **same prompt against a base model and a premium model — twice.** First on an **easy** task, then on a **hard** task. Every run, you measure two things: **the outcome (did it get it right?)** and **the token cost**. From that data you will build the skill this challenge is really about: deciding *which model to use for which job.* +In this challenge you will run the **same prompt against a base model and a premium model** on two very different kinds of task. First an **easy, checkable** task, then an **open-ended** one with no answer key. Every run, you measure the **outcome** — *did it get it right, or how good is it?* — and the **token cost**. From that data you will build the skill this challenge is really about: deciding *which model to use for which job.* > **Key Concept:** Lower cost per request is not the same as lower cost per *result*. ### Why this matters for coding -This challenge uses two short, easy-to-check prompts so the difference is obvious in seconds. But the lesson is the same one you face every time you code with Copilot: an agent constantly **reasons inside a task** — choosing logic, comparing values, judging whether its own output is correct. That is exactly where a weaker model is *confidently wrong*. Model selection governs the quality of that reasoning, not just whether code comes out. Pick the model that fits the *thinking* the task requires. +This challenge uses one quick checkable prompt and one open-ended planning prompt so you feel both sides of the trade-off. But the lesson is the same one you face every time you code with Copilot: an agent constantly **reasons inside a task** — choosing logic, weighing options, judging whether its own output is any good. That is exactly where a weaker model comes up short — sometimes *confidently wrong*, sometimes just shallow. Model selection governs the quality of that reasoning, not just whether output comes out. Pick the model that fits the *thinking* the task requires. ## Description @@ -29,7 +29,7 @@ You will run **two tasks**, each against **two models**: For every run, record the **outcome** (correct / incorrect) and the **token usage** (`View → Output → "GitHub Copilot Chat"`, and/or your Copilot usage view). If your environment doesn't surface an exact per-request token count, you can still see the pattern: the premium model produces far more text. Note *roughly how much more*. -> **Rule — no retries:** When the base model gets it wrong, **do not coach it or try again.** Record the failure and move on. The whole point is to see what each model produces *on the first shot* for each kind of task. (You'll reason about the cost of retrying in Part 2.) +> **Rule — first shot only:** Run each prompt **once** per model and record what you get. Don't coach, rerun, or rephrase to fish for a better result. The whole point is to see what each model produces *on the first attempt* for each kind of task. > **A note on token counts:** Exact token numbers vary run to run — premium reasoning models especially. Focus on the **pattern and the ratio**, not the absolute number. If a result looks odd, run it 2–3 times. @@ -59,48 +59,9 @@ Both models should get this right. Now compare the **token counts**. The premium --- -## Part 2 — A Hard Task (the base model should fail) +## Part 2 — An Open-Ended Task (judge the *quality*, not a right answer) -Now give **both** models this exact prompt: - -``` -The car wash is 40 meters from my home. I want to wash my car. -Should I walk or drive there? -``` - -✅ Correct answer: **Drive.** You can't wash a car that isn't there — the car has to be *at* the car wash. Walking the 40 meters leaves your car (and the problem) at home. The distance is a deliberate distraction. - -### Record - -| | Base model | Premium model | -|---|---|---| -| Answer (walk / drive) | ? | ? | -| Correct? | ? | ? | -| Total tokens | ? | ? | - -### What to notice - -The base model will very likely tell you to **walk** — "it's only 40 meters, it's greener, you'll get some exercise." It latches onto the short distance and misses the obvious point: *the car needs to come with you.* It is **confidently wrong**, and you can see it's wrong in one second — *that is the point.* - -The premium model reasons about the actual goal ("the car has to be at the wash to be cleaned → drive") and gets it right. Those extra tokens are not waste — they are the price of a *correct* answer. - -> Record the base model's wrong answer and stop — **don't rerun or rephrase it.** That single result is all you need. The next section is a calculation, not another run. - -### The cost of "just trying again" - -You won't actually retry here — but it's worth reasoning about, because in real work the temptation is "the base model costs less per call, I'll just rerun or rephrase until it gets it." Using the numbers you **already recorded above**: - -1. Take the base model's per-attempt cost and the cost of **one** premium-model call (use your org's per-request multipliers, or the token counts you just measured). - > **How many base-model attempts would it take to cost more than one premium-model call?** -2. Now the harder question: on a task like this — where the base model hits a **reasoning ceiling** — *would any number of attempts reliably get you the right answer?* (You already saw its single answer; capability, not luck, is the limit.) - -The trap: you could burn several low-cost attempts, pass the cost of one premium call, **and still not have a correct answer.** For a task the base model can't reason through, the only fix is a more capable model — not more attempts. - ---- - -## Part 3 — An Open-Ended Task (judge the *quality*, not a right answer) - -Parts 1 and 2 each had a checkable answer. **Most real work doesn't.** When you plan a feature, design a schema, or scope a project with Copilot, there's no answer key — *you* have to judge whether the output is any good. That judgment is the skill this part builds, and it's where model choice matters most. +Part 1 had a checkable answer. **Most real work doesn't.** When you plan a feature, design a schema, or scope a project with Copilot, there's no answer key — *you* have to judge whether the output is any good. That judgment is the skill this part builds, and it's where model choice matters most. Give **both** models this exact prompt: @@ -131,7 +92,7 @@ The base model tends to **charge straight ahead**: it assumes what the app is, p The premium model is more likely to **ask sharp clarifying questions first** (court booking? player matchmaking/ranking? score tracking? league scheduling? who are the users?) and to surface **deeper, domain-specific risks** — double-booking / concurrency on court reservations, ranking fairness, real-time score sync, geolocation privacy, no-show and cancellation handling. Those are exactly the risks that quietly derail a project. -> **The cost tie-in:** the premium plan costs more tokens up front. But a shallow plan isn't cheap — it's **deferred cost.** Every risk the base model *didn't* flag becomes rework, a rewrite, or a bug you pay for at execution time. On open-ended, high-leverage work, paying more for *deeper thinking* is usually the economical choice — the mirror image of Part 1, where paying more bought you nothing. +> **The cost tie-in:** the premium plan costs more tokens up front. But a shallow plan isn't cheap — it's **deferred cost.** Every risk the base model *didn't* flag becomes rework, a rewrite, or a bug you pay for at execution time — more *attempts* to get to something you can actually build. On open-ended, high-leverage work, paying more for *deeper thinking* is usually the economical choice — the mirror image of Part 1, where paying more bought you nothing. ### Questions to Answer @@ -141,26 +102,25 @@ The premium model is more likely to **ask sharp clarifying questions first** (co --- -## Part 4 — Compare Results & Decide +## Part 3 — Compare Results & Decide Combine your measurements into one table: -| Task | Base: correct? | Base: tokens | Premium: correct? | Premium: tokens | Which model should you use? | -|------|----------------|--------------|-------------------|-----------------|-----------------------------| -| Part 1 (easy) | ? | ? | ? | ? | ? | -| Part 2 (hard) | ? | ? | ? | ? | ? | -| Part 3 (open-ended) | judge quality | ? | judge quality | ? | ? | +| Task | Base: outcome | Base: tokens | Premium: outcome | Premium: tokens | Which model should you use? | +|------|---------------|--------------|------------------|-----------------|-----------------------------| +| Part 1 (easy, checkable) | correct? | ? | correct? | ? | ? | +| Part 2 (open-ended) | judge quality | ? | judge quality | ? | ? | ### Questions to Answer 1. On the **easy** task, which model gave the better *value* (correct answer, fewest tokens)? -2. On the **hard** task, what did the base model's wrong answer actually "cost" you, even though each attempt was low-cost? -3. If you ran each task **10,000 times a day**, how would your model choice differ between Part 1 and Part 2? -4. How would you decide, *before* running a task, whether it is a "Part 1" (easy → base) or a "Part 2" (hard → premium) task? +2. On the **open-ended** task, did the premium model's extra tokens buy you something real — depth, clarifying questions, risks the base model missed? +3. If you ran the **easy** task **10,000 times a day**, which model would you pick, and how much would the wrong choice cost you? +4. How would you decide, *before* running a task, whether it is a "Part 1" (well-defined → base) or a "Part 2" (open-ended, judgment-heavy → premium) task? --- -## Part 5 — Classify Your Own Tasks +## Part 4 — Classify Your Own Tasks The skill this challenge builds is *prediction*: knowing which tier a task needs **before** you spend anything. @@ -194,18 +154,16 @@ Output only the code. No explanation, no markdown fences. Record the token difference. Constraining output — "code only", "answer only", "explain in under 50 words", a JSON schema — drops the cost while keeping the correct result. -> Note: constraints reduce **output** tokens. They help most when the model would otherwise pad the answer with explanation. They do **not** make a wrong model right (see Part 2), and they do little when the output is already terse or when a reasoning model's hidden "thinking" tokens dominate. +> Note: constraints reduce **output** tokens. They help most when the model would otherwise pad the answer with explanation. They do **not** turn a shallow answer into a good one (see Part 2), and they do little when the output is already terse or when a reasoning model's hidden "thinking" tokens dominate. ## Success Criteria To complete this challenge successfully, you should be able to: - Run the same prompt against a base and a premium model for both tasks -- Record outcome (correct/incorrect) and token usage for all four runs +- Record the outcome (correct/incorrect, or quality score) and token usage for all four runs - Show that on the easy task the base model was correct **and** used fewer tokens -- Show that on the hard task the base model was confidently wrong while the premium model was correct - On the open-ended planning task, judge each model's *quality* against the rubric (clarifying questions, depth of the top-5 risks, specificity, trust-to-start) and explain which you'd build from -- Reason about how many base-model retries it would take to cost more than one premium call — and why retries can't fix a reasoning-ceiling task - Classify two of your own real tasks by tier and verify your prediction - (Optional) Demonstrate a token reduction by adding an output constraint to a verbose task @@ -226,5 +184,5 @@ To complete this challenge successfully, you should be able to: ## Reflection Questions 1. Describe a real task from your own work that is a "Part 1" task. Which model would you use and why? -2. Describe a real "Part 2" task. How would you justify the premium multiplier to your team? +2. Describe a real "Part 2" task — open-ended, judgment-heavy. How would you justify the premium multiplier to your team? 3. How could you combine base and premium models in a single workflow to minimize total cost (e.g., base model drafts, premium model reviews)? From 37e86ca8cab8af9f5a938521cc280df281e56e32 Mon Sep 17 00:00:00 2001 From: Andressa Siqueira <62267346+AndressaSiqueira@users.noreply.github.com> Date: Fri, 7 Aug 2026 15:03:04 -0300 Subject: [PATCH 37/48] Revise Challenge 01 for clarity and structure Updated the challenge description to clarify the difference between direct prompting and spec-driven development using GitHub Copilot. Adjusted the structure and content to enhance understanding of the experiment objectives and requirements. --- .../Student/Challenge-01.md | 353 +++++++++--------- 1 file changed, 178 insertions(+), 175 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md index 634b841e21..2b198a8c3d 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md @@ -1,275 +1,278 @@ -# Challenge 01 - Spec-Driven Development with Spec Kit +# Challenge 01 - Direct Prompt vs. Spec-Driven Development [< Previous Challenge](./Challenge-00.md) - **[Home](../README.md)** - [Next Challenge >](./Challenge-02.md) ## Introduction -In this challenge, you will experience the difference between **ad-hoc prompting** and **spec-driven development** by building the same application twice — first without structure, then using **GitHub Spec Kit**. +In this challenge, you will build the same application twice with GitHub Copilot: -Spec Kit is one of several ways to implement spec-driven development with GitHub Copilot. The core principle applies regardless of tooling: **structured context produces better results than conversational prompts**. +1. Using only a direct prompt +2. Using a structured specification in a Markdown file -With Spec Kit, you will: +The goal is not to prove in advance that one approach is always better. The goal is to observe how the level of detail in the context affects time, credit consumption, the number of interruptions, and the delivered result. -- Define a **constitution (rules)** -- Create a **spec (what to build)** -- Generate a **plan (how to build)** -- Break it into **tasks** -- Execute implementation +This activity uses **Spec-Driven Development (SDD)**. The specification will be provided in a single `sdd.md` file, without a constitution, special commands, a separate plan, or a task list. -**Goal:** Experience firsthand how structured specs reduce token usage and improve output quality compared to ad-hoc prompting. +> **Key concept:** in SDD, the specification becomes the source of context for implementation. -> **Key Concept:** Spec becomes your context. Not the chat. +## Experiment Objective -## Description +Both approaches must build the same application with the same technology, model, and scope. -In this challenge, you will build **the same application twice**: +### Application -1. **Part 1:** Build with ad-hoc prompting (no structure) -2. **Part 2:** Build with Spec Kit workflow +A simple notes application built with React and TypeScript. -Then compare the results. +Requirements: -### The Application +1. Create, read, update, and delete notes (CRUD) +2. Each note must have a required title and optional content +3. Notes must exist only in the application's in-memory state +4. Do not use a backend, database, persistent storage, or automated tests +5. The application must be implemented and run locally -You will build: +## Preparation -> **A simple notes application** +To make the comparison more consistent: -Requirements: -1. Create, read, update, and delete notes (CRUD) -2. Each note must have a title (required) and content +- Use the same computer and environment +- Use the same versions of VS Code and GitHub Copilot +- Use the same model in both runs +- Start each approach in an empty folder and a new conversation +- Do not reuse files generated by one approach in the other +- Start measuring when you send the implementation instruction +- Stop measuring when the application is running and the CRUD operations have been verified manually -That's it — keep it simple! +Also record the time and cost required to prepare the specification. They will be analyzed separately from implementation time. --- -## Part 1 — Build with Ad-Hoc Prompting - -First, build the application using traditional conversational prompting with Copilot. +## Part 1 - Implementation with a Direct Prompt -### Step 1 — Create a New Project Folder +### Step 1 - Create an Empty Folder ```bash -mkdir notes-app-adhoc -cd notes-app-adhoc +mkdir notes-app-prompt +cd notes-app-prompt code . ``` -### Step 2 — Build the Application +### Step 2 - Start a New Conversation -Your goal: Create a working notes application that meets the 2 requirements above. +Select the model chosen for the experiment and send only the prompt below: -**Rules:** -- Use only Copilot Chat with ad-hoc prompts -- No pre-written specs or documentation -- Just start prompting and see what happens +```text +Build a simple notes application using React and TypeScript. -**Try to complete the application on your own!** +Requirements: + +1. Create, read, update, and delete notes. +2. Each note must have a required title and optional content. +3. Store notes only in the application's in-memory state. +4. Do not use a backend, database, persistent storage, or automated tests. + +Implement the complete application in local machine. +``` -### Step 3 — Track Your Experience +### Step 3 - Record the Run -As you work, note: -- How many prompts did you need? -- How many times did you repeat the same information? -- Did Copilot "forget" what you asked earlier? -- Was the generated code consistent in style? -- How did it feel? +Record the start and end times, credits consumed, questions asked by Copilot, dependency decisions requested, required interventions, and any errors or rework. -### Step 4 — Save Your Results +Answer the questions required to allow the process to continue, but record each interruption. -Keep this project. You'll compare it later. +### Step 4 - Verify Manually + +Confirm that you can: + +- Create a note with a title and content +- Create a note without content +- Prevent the creation of a note without a title +- View the created notes +- Update a note's title and content +- Delete a note +- Reload the page and observe that the data may be lost + +Keep the project for the final comparison. --- -## Part 2 — Build with Spec Kit +## Part 2 - Implementation with SDD -Now build the **same application** using the Spec Kit workflow. +In this part, the same application will be built from a previously prepared specification. -### Step 1 — Initialize a New Spec Kit Project +### Step 1 - Create a New Empty Folder ```bash -specify init notes-app-speckit --integration copilot -cd notes-app-speckit +mkdir notes-app-sdd +cd notes-app-sdd code . ``` -### Step 2 — Verify Spec Kit is Ready +### Step 2 - Create the Specification File -In the project folder, you should see: -- `.specify/` -- `.github/prompts/` -- Markdown files +In the root of the folder, create a file named `sdd.md` with the following content: -In Copilot Chat, type `/` — you should see: -- `/speckit.constitution` -- `/speckit.specify` -- `/speckit.plan` -- `/speckit.tasks` -- `/speckit.implement` +```markdown +# Specification: Simple Notes Application -### Step 3 — Define Constitution +## Objective -In Copilot Chat, run: +Build a complete notes application using React and TypeScript that runs +on the local machine. The application must allow users to create, read, +update, and delete notes. -``` -/speckit.constitution -``` +## Technology -Then describe your rules. Example: +- React +- TypeScript +- Local development environment -``` -Simple local application. Clean code with clear separation of concerns. -``` +## Note Data Model -This creates the `constitution.md` file containing your system rules. +Each note must contain: -### Step 4 — Create Spec +| Field | Type | Required | Description | +|---|---|---|---| +| id | string or number | Yes | Unique identifier generated by the application | +| title | string | Yes | Title of the note | +| content | string | No | Optional content of the note | -Run: +## Functional Requirements -``` -/speckit.specify -``` +### REQ-001: Create notes -Describe the same requirements as Part 1: +The user must be able to create a note with a required title and optional +content. A valid note must be added to the in-memory state and displayed. -``` -A notes application with CRUD operations. -Each note has a title (required) and content. -``` +### REQ-002: Read notes -This creates a `spec.md` file with: -- Requirements -- Acceptance criteria -- User stories +The application must display the notes created during the current session, +including each note's title and its content when present. -### Step 5 — (Optional) Clarify +### REQ-003: Update notes -Run: +The user must be able to update the title and content of an existing note. +The update must replace the existing note without creating a duplicate. -``` -/speckit.clarify -``` +### REQ-004: Delete notes -Spec Kit will ask clarifying questions to improve your spec. This: -- Reduces ambiguity -- Reduces rework later +The user must be able to delete an existing note. The deleted note must be +removed from memory and no longer displayed. -### Step 6 — Generate Plan +### REQ-005: Required title -Run: +The application must not create or update a note with an empty title. The +content may be empty. -``` -/speckit.plan -``` +### REQ-006: In-memory state -This generates: -- Architecture decisions -- Technology stack -- Project structure +Notes must be managed only in client-side application state. Notes may be +lost when the page is refreshed or the application is restarted. -### Step 7 — Generate Tasks +## Constraints -Run: +- Use React and TypeScript +- Run on the local machine +- Do not use a backend +- Do not use a database +- Do not use localStorage, IndexedDB, files, or other persistent storage +- Do not include automated tests -``` -/speckit.tasks +## Definition of Done + +The application is complete when it runs locally and the user can create, +read, update, and delete notes while all constraints above are respected. ``` -This creates: -- List of small, actionable tasks -- Execution order +### Step 3 - Start a New Conversation -### Step 8 — Implement +Select the same model used in Part 1 and send: -Run: +```text +Read the sdd.md file in this project and implement the complete application +described in it on the local machine. -``` -/speckit.implement +Follow the specification exactly. Do not add requirements or functionality +outside the defined scope. ``` -Now Copilot will: -- Execute tasks sequentially -- Generate code incrementally +### Step 4 - Record and Verify + +Record the same measurements as in Part 1 and use exactly the same manual checklist. Do not give SDD an advantage for features that were not included in the specification. --- -## Part 3 — Compare Results +## Part 3 - Compare the Results -Now compare both implementations. +Complete the table with data from both runs: -### Questions to Answer +| Aspect | Direct prompt | SDD with a ready specification | +|---|---:|---:| +| Model used | | | +| Implementation time | | | +| Credits consumed during implementation | | | +| Questions during the run | | | +| User interventions | | | +| Requirements met | | | +| Errors or rework | | | +| Qualitative UX assessment | | | -| Aspect | Ad-Hoc Approach | Spec Kit Approach | -|--------|-----------------|-------------------| -| Total prompts needed | ? | ? | -| Times you repeated context | ? | ? | -| Code consistency | ? | ? | -| Time to complete | ? | ? | -| Quality of output | ? | ? | +### Three Dimensions of Analysis -### What to Look For +1. **Effectiveness:** did both applications meet the same requirements? +2. **Implementation efficiency:** which approach required less time, fewer credits, and fewer interventions after its input was ready? +3. **Full-cycle efficiency:** does the result change when the cost of preparing the specification is included? -- **Context retention:** Did Copilot remember requirements? -- **Consistency:** Did the code follow the same patterns throughout? -- **Completeness:** Were all requirements addressed? -- **Token efficiency:** How much did you have to type? +The total SDD time and cost must be calculated as: -## Rules +$$ +T_{SDD\ total} = T_{specification} + T_{implementation} +$$ -- Complete Part 1 before starting Part 2 -- Do NOT skip steps in the Spec Kit workflow -- Review each output before continuing -- Make minimal edits — avoid rewriting everything -- Document your observations for comparison +$$ +C_{SDD\ total} = C_{specification} + C_{implementation} +$$ -## Success Criteria +Do not mix these two perspectives. A ready specification may speed up implementation, but preparing it also has a cost. -To complete this challenge successfully, you should be able to: -- Build the task management API using ad-hoc prompting -- Build the same API using Spec Kit workflow -- Create a constitution that defines project rules and standards -- Generate a spec from your requirements description -- Produce a structured plan from the spec -- Break the plan into executable tasks -- Compare both approaches and articulate the differences -- Demonstrate reduced token usage with spec-driven development -- Show improved output consistency and predictability +## Success Criteria -## Learning Resources +After completing the challenge, you should be able to: -- [GitHub Spec Kit Repository](https://github.com/github/spec-kit) -- [Spec Kit Installation Guide](https://github.com/github/spec-kit/blob/main/docs/installation.md) -- [Spec-Driven Development with GitHub Spec Kit](https://medium.com/@vamshi.rapolu/spec-driven-development-with-github-spec-kit-copilot-in-vs-code-new-existing-projects-2531d10bd61d) -- [Spec Kit Commands Reference](https://easyguides.net/guides/spec-kit/commands) -- [Plan and Tasks Commands Tutorial](https://codestandup.com/posts/2025/github-spec-kit-tutorial-plan-tasks-commands/) +- Build the same application with a direct prompt and a Markdown specification +- Keep the technology, model, and scope equivalent in both runs +- Verify the CRUD operations and constraints manually +- Compare time, credits, questions, and interventions +- Separate implementation cost from preparation cost +- Explain why a functional tie can still show differences in efficiency +- Recognize that a single run is an observation, not universal proof -## Tips +## Reflection Questions -- Part 1 intentionally feels inefficient — that's the point! -- Spec becomes your persistent context — no need to repeat requirements -- The constitution acts as guardrails that apply to all generated code -- Use `/speckit.clarify` when requirements feel ambiguous -- Each step builds on the previous — the workflow is designed to be sequential -- Review generated specs and plans before proceeding to catch issues early -- Small, focused specs produce better results than large, vague ones +1. Did both approaches meet the same functional requirements? +2. Which approach required more decisions during implementation? +3. Did the specification reduce ambiguity, or did it only move decisions to an earlier stage? +4. How much time and how many credits were used to prepare the specification? +5. Does the result change when that cost is included? +6. In which situations could the specification be reused and offset its initial cost? +7. Would a larger application or a later requirements change produce the same result? -## Reflection Questions +## Experiment Limitations -After completing this challenge, answer: +- A single run does not control for the natural variation in model responses +- The application is small and may favor the direct prompt over the full cycle +- The visual assessment is subjective without predefined criteria +- Time may be affected by installations, network conditions, and familiarity with the tools +- The results do not demonstrate that SDD is always better or worse -1. How did Part 1 (ad-hoc) feel compared to Part 2 (Spec Kit)? -2. How many times did you repeat context in each approach? -3. Did the outputs become more predictable with Spec Kit? -4. How would spec-driven development impact token usage and costs in real projects? -5. What other tools or methods could achieve similar spec-driven benefits? +## Additional Challenge -## Advanced Challenges +After completing both versions, give both of them the same requirements change: -Too comfortable? Try these: +```text +Add a status field with the values draft and published. New notes must start +as draft, and published notes cannot be edited until changed back to draft. +``` -- Apply Spec Kit to an existing project instead of a new one -- Create multiple specs for different features and observe how they interact -- Measure credit consumption between both approaches for the same feature -- Customize the constitution for different project types (frontend, backend, full-stack) +For the SDD version, update the `sdd.md` file first. Then compare time, credits, questions, and rework again. This second round helps evaluate whether the specification provides more value as the software evolves. From fa3ac3e27fef006a6f9a470866d725c845fb9417 Mon Sep 17 00:00:00 2001 From: Andressa Siqueira <62267346+AndressaSiqueira@users.noreply.github.com> Date: Fri, 7 Aug 2026 15:04:53 -0300 Subject: [PATCH 38/48] Remove additional challenge from Challenge-01.md Removed additional challenge section regarding status field updates and comparisons. --- .../Student/Challenge-01.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md index 2b198a8c3d..c7176a805d 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md +++ b/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md @@ -266,13 +266,3 @@ After completing the challenge, you should be able to: - Time may be affected by installations, network conditions, and familiarity with the tools - The results do not demonstrate that SDD is always better or worse -## Additional Challenge - -After completing both versions, give both of them the same requirements change: - -```text -Add a status field with the values draft and published. New notes must start -as draft, and published notes cannot be edited until changed back to draft. -``` - -For the SDD version, update the `sdd.md` file first. Then compare time, credits, questions, and rework again. This second round helps evaluate whether the specification provides more value as the software evolves. From 68c5eaa4c7be457c324c5d97813f35517d2d4015 Mon Sep 17 00:00:00 2001 From: Andressa Siqueira <62267346+AndressaSiqueira@users.noreply.github.com> Date: Mon, 24 Aug 2026 14:11:12 -0300 Subject: [PATCH 39/48] Revise Challenge 01 Coach's Guide for clarity Updated the Coach's Guide for Challenge 01 to enhance clarity and structure, including detailed instructions for comparing direct prompting with Spec-Driven Development. --- .../Coach/Solution-01.md | 297 +++++++++++------- 1 file changed, 183 insertions(+), 114 deletions(-) diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md b/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md index 6b3e6e7c65..8d74e6bae4 100644 --- a/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md +++ b/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md @@ -2,168 +2,237 @@ [< Previous Solution](./Solution-00.md) - **[Home](./README.md)** - [Next Solution >](./Solution-02.md) -## Notes & Guidance +# Coach Guide: Direct Prompt vs. Spec-Driven Development -This challenge introduces students to **spec-driven development** by having them build the **same simple application twice**: first with ad-hoc prompting, then with **GitHub Spec Kit**. The hands-on comparison makes the benefits tangible. +## Purpose -> **Note:** Spec Kit installation prerequisites are covered in Challenge 0. If students haven't completed setup, direct them there first. +This guide helps coaches facilitate an experiment comparing two ways of building the same React and TypeScript application with GitHub Copilot: -### The Application +1. A direct implementation prompt. +2. A structured Markdown specification using Spec-Driven Development (SDD). -Students build a **simple notes app** with only 2 requirements: -1. CRUD operations for notes -2. Each note has a title (required) and content +The goal is not to prove that one approach is universally better. Participants should observe how context influences implementation time, credit consumption, interruptions, interventions, rework, and the delivered application. -This is intentionally simple — the goal is to compare approaches, not build something complex. +## Learning Outcomes -### Key Concepts to Explain +By the end of the activity, participants should be able to: -**Why Two Applications?** +- Explain the role of a specification as implementation context. +- Compare direct prompting and SDD under equivalent conditions. +- Distinguish functional effectiveness from implementation efficiency. +- Include specification preparation when evaluating full-cycle efficiency. +- Discuss experimental results without generalizing from a single run. -Building the same thing twice demonstrates: -- How much context repetition happens with ad-hoc prompting -- How structured specs reduce cognitive load and token usage -- The difference in output consistency +## Recommended Duration -**Part 1 is Intentionally Unguided:** +| Activity | Suggested time | +|---|---:| +| Introduction and environment check | 10 minutes | +| Direct prompt implementation | 20–30 minutes | +| SDD implementation | 20–30 minutes | +| Comparison and discussion | 20 minutes | +| Total | 70–90 minutes | -Students don't get example prompts — they figure it out themselves. This: -- Creates authentic frustration with ad-hoc prompting -- Makes the Spec Kit workflow feel like a relief -- Produces genuine observations for comparison +Do not impose an implementation time limit if it would prevent participants from completing and manually verifying the application. -**Spec Kit is One Approach:** +## Coach Preparation -Emphasize that Spec Kit is **one of many** ways to do spec-driven development. The principle — structured context produces better results — applies regardless of tooling. Other approaches include: -- Custom instruction files (.github/copilot-instructions.md) -- Manual spec documents referenced in prompts -- Project constitution patterns -- Prompt template systems +Before the session: -**Spec Kit Workflow:** +- Confirm that VS Code, Node.js, npm, and GitHub Copilot are available. +- Select one GitHub Copilot model to use in both runs. +- Keep the provided `sdd.md` content available. +- Prepare a timer and measurement worksheet. +- Ensure participants can inspect Copilot credit consumption. +- Ask participants to close unrelated conversations and projects. +- Explain that generated files cannot be reused between runs. -1. **Constitution:** Project-wide rules and constraints (architecture, standards, patterns) -2. **Spec:** What to build (requirements, acceptance criteria, user stories) -3. **Plan:** How to build it (architecture, stack, structure) -4. **Tasks:** Actionable work items (small, ordered, executable) -5. **Implement:** Execute tasks with Copilot +The folders must begin empty. Existing scaffolds, templates, or files may affect the comparison and should be recorded if used. -**Why This Reduces Cost:** +## Fairness Rules -- Spec becomes persistent context — no need to repeat in every prompt -- Constitution provides guardrails that apply automatically -- Structured workflow prevents expensive backtracking -- Small tasks produce more predictable outputs than large prompts -- Clarification step catches ambiguity before implementation +The coach must enforce the following controls: -### Expected Time +- Same computer and environment. +- Same VS Code and GitHub Copilot versions. +- Same Copilot model. +- Same application scope and manual verification checklist. +- Separate empty folders and new conversations. +- No reuse of generated code between runs. +- No additional implementation instructions unless required to unblock progress. +- Every clarification, correction, or intervention must be recorded. -45-75 minutes: -- 15-20 minutes: Part 1 — Build with ad-hoc prompting -- 20-30 minutes: Part 2 — Build with Spec Kit workflow -- 10-15 minutes: Part 3 — Compare results and discussion +Do not steer Copilot toward a specific framework choice, package, UI design, or solution unless the participant is blocked. Any such assistance counts as an intervention. -### Troubleshooting +## Facilitation Flow -**Spec Kit Commands Not Appearing in Copilot Chat:** +### 1. Introduce the Experiment -1. Verify `.github/prompts/` folder exists with Spec Kit files -2. Reload VS Code window (Ctrl+Shift+P → "Developer: Reload Window") -3. Ensure Copilot Chat extension is up to date +Explain that the experiment evaluates three dimensions: -**Integration Issues:** +- **Effectiveness:** whether the application satisfies the requirements. +- **Implementation efficiency:** effort after the prompt or specification is ready. +- **Full-cycle efficiency:** implementation effort plus specification preparation. -If `--integration copilot` fails, try initializing without integration first: -```bash -uvx --from git+https://github.com/github/spec-kit.git specify init my-project -``` -Then manually copy prompt files to `.github/prompts/`. +Remind participants that a functional tie can still reveal differences in time, cost, ambiguity, and rework. -### Success Criteria Validation +### 2. Run the Direct Prompt Approach -Students should be able to demonstrate: +Before the participant submits the prompt: -**Part 1 — Ad-Hoc Approach:** -1. Created task-api-adhoc project -2. Built the API using conversational prompts -3. Documented observations (context repetition, inconsistencies) +- Confirm the folder is empty. +- Confirm a new Copilot conversation is open. +- Record the selected model. +- Prepare the timer. -**Part 2 — Spec Kit Approach:** -1. **Setup Complete:** `.specify/` and `.github/prompts/` folders exist -2. **Constitution Created:** `constitution.md` with project rules -3. **Spec Generated:** `spec.md` with requirements and acceptance criteria -4. **Plan Produced:** Architecture and structure decisions documented -5. **Tasks Listed:** Ordered list of small, actionable items -6. **Implementation Started:** At least one task executed with Copilot +Start timing when the implementation prompt is sent. During execution, observe without directing the participant. -**Part 3 — Comparison:** -1. Completed the comparison table -2. Can articulate differences between approaches -3. Understands why structured specs reduce token usage +Record: -### Common Blockers +- Start and end time. +- Credits consumed. +- Questions asked by Copilot. +- Dependency or tooling decisions requested. +- Participant interventions. +- Errors, failed commands, and rework. +- Any functionality added beyond the requested scope. -**Students Skip Steps:** +Stop timing only after the application is running and the full manual checklist has been completed. -Emphasize the workflow is sequential by design. Each step builds on the previous. Skipping to `/speckit.implement` without a spec produces the same results as ad-hoc prompting. +### 3. Run the SDD Approach -**Vague Constitution:** +Before the second run: -Guide them to be specific. Bad: "Good code." Good: "Node.js with TypeScript, Express framework, repository pattern, input validation with Joi." +- Confirm a different empty folder is being used. +- Create the provided `sdd.md` in the project root. +- Open a new Copilot conversation. +- Select the same model. +- Verify that no files from the first implementation were reused. -**Spec Too Large:** +Start timing when the participant sends the instruction to read and implement `sdd.md`. -If the spec covers too much, `/speckit.plan` and `/speckit.tasks` become unwieldy. Encourage smaller, focused specs for individual features. +Apply the same observation and stopping rules used in the direct prompt run. Do not give the SDD implementation credit for additional features that were not required by the specification. -**Students Want to Edit Generated Files:** +### 4. Perform Manual Verification -This is fine! The generated specs/plans are starting points. Encourage editing for accuracy before proceeding. +Use exactly the same checklist for both applications: -### Hints to Share +- [ ] Create a note with a title and content. +- [ ] Create a note without content. +- [ ] Reject creation when the title is empty or whitespace-only. +- [ ] Display all notes created during the session. +- [ ] Update an existing note’s title and content. +- [ ] Reject an update with an empty title. +- [ ] Update without creating a duplicate note. +- [ ] Delete an existing note. +- [ ] Confirm that the deleted note disappears. +- [ ] Reload the page and confirm that notes may be lost. +- [ ] Confirm no backend, database, or persistent storage is used. +- [ ] Confirm no automated tests were added. -- Use `/speckit.clarify` whenever you feel the spec is ambiguous — it's designed to ask the right questions -- The constitution applies to everything — write it once, benefit everywhere -- Review the plan before generating tasks — it's easier to fix architecture issues at the plan stage -- Tasks should be small enough to complete in a single Copilot interaction -- You can re-run any command to regenerate — the workflow is iterative +Record failures and corrections instead of silently fixing them. -### Reflection Discussion Points +## Measurement Definitions -After completion, discuss with students: +Use consistent definitions across both runs: -1. **Experience Difference:** How did Part 1 feel compared to Part 2? -2. **Context Repetition:** How many times did they repeat requirements in each approach? -3. **Consistency:** Was the Spec Kit output more predictable? -4. **Token Impact:** Fewer retries, less context repetition = lower token usage -5. **Other Approaches:** What other methods could achieve similar structured benefits? +- **Question:** Copilot explicitly requests information or a decision. +- **Interruption:** progress pauses because participant input is required. +- **Intervention:** the participant supplies a correction, additional instruction, command, or code change. +- **Error:** a build, runtime, dependency, or functional failure. +- **Rework:** work required to correct a missing or incorrect result. +- **Implementation time:** time from sending the implementation instruction until the application runs and passes manual verification. +- **Specification preparation cost:** time and credits used to author or refine the specification, excluding implementation. -### Key Insight for Students +If the specification was supplied ready-made, record its known preparation cost separately. If that cost is unavailable, mark it as “not measured” rather than treating it as zero. -> **Spec becomes your context. Not the chat.** +## Results Worksheet -Traditional prompting requires repeating context every time. With Spec Kit, the spec IS the context that Copilot references. This is both better engineering and better token economics. +| Aspect | Direct prompt | SDD with ready specification | +|---|---:|---:| +| Model used | | | +| Implementation time | | | +| Implementation credits | | | +| Questions asked | | | +| Interruptions | | | +| User interventions | | | +| Errors | | | +| Rework actions | | | +| Requirements passed | /12 | /12 | +| Out-of-scope features | | | +| Qualitative UX score | /5 | /5 | -### Coaching Part 1 (Ad-Hoc) +Record SDD preparation separately: -Let students experience the frustration! Don't intervene too quickly. Common observations: -- They had to repeat "use Node.js" multiple times -- Copilot "forgot" earlier requirements -- Code style was inconsistent between prompts -- They felt like they were re-explaining constantly +| Specification metric | Result | +|---|---:| +| Preparation time | | +| Preparation credits | | +| Number of revisions | | -This pain is what makes Part 2 powerful. +Calculate full-cycle SDD values as: -### Demo Script (If Students Struggle) +$$ +T_{\mathrm{SDD\ total}} += +T_{\mathrm{specification}} ++ +T_{\mathrm{implementation}} +$$ -1. Initialize project: Show the generated folder structure -2. Run `/speckit.constitution` and show resulting file -3. Run `/speckit.specify` with a simple requirement -4. Show how `/speckit.plan` produces architecture from the spec -5. Run `/speckit.tasks` and show the task breakdown -6. Execute one task with `/speckit.implement` +$$ +C_{\mathrm{SDD\ total}} += +C_{\mathrm{specification}} ++ +C_{\mathrm{implementation}} +$$ + +## Qualitative UX Guidance + +To reduce subjectivity, score both applications from 1 to 5 using the same criteria: + +- Form and action clarity. +- Validation feedback. +- Note readability. +- Discoverability of edit and delete actions. +- Overall consistency and usability. -### Connection to Other Challenges - -- **Challenge 04 (Prompt Architecture):** Spec Kit is a formalized version of structured prompting -- **Challenge 06 (Token Golf):** Spec Kit naturally reduces tokens by eliminating context repetition -- **Challenge 07 (Infrastructure):** Constitution can encode infrastructure standards +Visual polish is secondary. It must not compensate for missing functional requirements. + +## Debrief Questions + +Ask participants: + +1. Did both applications satisfy the same requirements? +2. Which approach required more decisions during implementation? +3. Which ambiguities appeared in the direct prompt run? +4. Did SDD eliminate ambiguity or move decisions to specification preparation? +5. Which approach used less implementation time and fewer credits? +6. Does the conclusion change when specification preparation is included? +7. What specification content had the greatest implementation impact? +8. Which parts of the specification could be reused? +9. How might a larger application change the outcome? +10. How might later requirement changes affect each approach? + +## Coaching Notes + +Avoid announcing an expected winner. Common valid outcomes include: + +- Both approaches deliver equivalent applications. +- SDD reduces interruptions but costs more overall for a small application. +- The direct prompt is faster but requires more decisions or corrections. +- The structured specification improves consistency without reducing credits. +- Natural model variation outweighs the difference between approaches. + +Treat every result as an observation, not proof. Encourage participants to describe what happened, identify contributing factors, and state the experiment’s limitations. + +## Completion Criteria + +The challenge is complete when: + +- Both applications have been built independently. +- Both have been evaluated with the same checklist. +- All measurements and interventions have been recorded. +- Implementation and specification preparation costs remain separate. +- Participants can explain the observed tradeoffs and limitations. From c9d03530b58c4831bacba7854115e8c2eb0fb995 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Mon, 31 Aug 2026 09:59:26 -0700 Subject: [PATCH 40/48] Add contributors to README.md --- xxx-GitHubCopilotCostOptimization/README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/xxx-GitHubCopilotCostOptimization/README.md b/xxx-GitHubCopilotCostOptimization/README.md index f57ec91e69..73f26ccf6d 100644 --- a/xxx-GitHubCopilotCostOptimization/README.md +++ b/xxx-GitHubCopilotCostOptimization/README.md @@ -48,3 +48,7 @@ In this hack, you will learn practical techniques to optimize GitHub Copilot usa ## Contributors - Andy Huang +- Andressa Siqueira +- Anastasia Nefedova +- Anahita Afshari +- Devanshi Thakar From b07aca325fde7ebc278a604a78fc5cd2a773bd46 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Mon, 31 Aug 2026 10:16:08 -0700 Subject: [PATCH 41/48] Updating number to 076 --- .../devcontainer.json | 6 +++--- .../Coach/Lectures.pptx | Bin .../Coach/README.md | 0 .../Coach/Solution-00.md | 0 .../Coach/Solution-01.md | 0 .../Coach/Solution-02.md | 0 .../Coach/Solution-03.md | 0 .../Coach/Solution-04.md | 0 .../Coach/Solution-05.md | 0 .../Coach/Solution-06.md | 0 .../Coach/Solutions/.gitkeep | 0 .../.github/copilot-instructions.md | 0 .../.github/instructions/api.instructions.md | 0 .../.github/instructions/events.instructions.md | 0 .../.github/skills/free-events-endpoint/SKILL.md | 0 .../Challenge-02-NYCApp-Solutions/README.md | 0 .../src/data/events.ts | 0 .../src/data/neighborhoods.ts | 0 .../src/data/restaurants.ts | 0 .../src/routes/events.ts | 0 .../src/routes/neighborhoods.ts | 0 .../src/routes/restaurants.ts | 0 .../Challenge-03-ModelSelection-Solutions/README.md | 0 .../Challenge-03-ModelSelection-Solutions/TODO.md | 0 .../harness.py | 0 .../results.md | 0 .../README.md | 0 .../Student/Challenge-00.md | 0 .../Student/Challenge-01.md | 0 .../Student/Challenge-02.md | 0 .../Student/Challenge-03.md | 0 .../Student/Challenge-04.md | 0 .../Student/Challenge-05.md | 0 .../Student/Challenge-06.md | 0 .../Resources/.devcontainer/devcontainer.json | 2 +- .../Student/Resources/.gitkeep | 0 .../.github/copilot-instructions.md | 0 .../Student/Resources/Challenge-02-NYCApp/README.md | 0 .../Challenge-02-NYCApp/src/data/events.ts | 0 .../Challenge-02-NYCApp/src/data/neighborhoods.ts | 0 .../Challenge-02-NYCApp/src/data/restaurants.ts | 0 .../Challenge-02-NYCApp/src/routes/events.ts | 0 .../Challenge-02-NYCApp/src/routes/neighborhoods.ts | 0 .../Challenge-02-NYCApp/src/routes/restaurants.ts | 0 .../Resources/Challenge-03-ModelSelection/README.md | 0 .../measurements-template.md | 0 .../output-constraints.md | 0 .../Challenge-03-ModelSelection/prompts.md | 0 .../Student/Resources/Challenge06/data/sales.csv | 0 49 files changed, 4 insertions(+), 4 deletions(-) rename .devcontainer/{xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/devcontainer.json (83%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Lectures.pptx (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/README.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solution-00.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solution-01.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solution-02.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solution-03.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solution-04.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solution-05.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solution-06.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/.gitkeep (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/neighborhoods.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/restaurants.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/events.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/neighborhoods.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/restaurants.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/README.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Challenge-00.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Challenge-01.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Challenge-02.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Challenge-03.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Challenge-04.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Challenge-05.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Challenge-06.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/.devcontainer/devcontainer.json (94%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/.gitkeep (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-02-NYCApp/README.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-02-NYCApp/src/data/events.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-02-NYCApp/src/data/neighborhoods.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-02-NYCApp/src/data/restaurants.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-02-NYCApp/src/routes/events.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-02-NYCApp/src/routes/neighborhoods.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-02-NYCApp/src/routes/restaurants.ts (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-03-ModelSelection/README.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-03-ModelSelection/measurements-template.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-03-ModelSelection/output-constraints.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge-03-ModelSelection/prompts.md (100%) rename {xxx-GitHubCopilotCostOptimization => 076-GitHubCopilotCostOptimization}/Student/Resources/Challenge06/data/sales.csv (100%) diff --git a/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json b/.devcontainer/076-GitHubCopilotCostOptimization/devcontainer.json similarity index 83% rename from .devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json rename to .devcontainer/076-GitHubCopilotCostOptimization/devcontainer.json index 310bc826a5..84e10376c4 100644 --- a/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json +++ b/.devcontainer/076-GitHubCopilotCostOptimization/devcontainer.json @@ -1,7 +1,7 @@ { - "name": "xxx-GitHubCopilotCostOptimization", + "name": "076-GitHubCopilotCostOptimization", "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", - "workspaceFolder": "/workspace/xxx-GitHubCopilotCostOptimization/Student/Resources", + "workspaceFolder": "/workspace/076-GitHubCopilotCostOptimization/Student/Resources", "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached", "hostRequirements": { "cpus": 2 @@ -20,7 +20,7 @@ }, "codespaces": { "openFiles": [ - "xxx-GitHubCopilotCostOptimization/Student/Resources/README.md" + "076-GitHubCopilotCostOptimization/Student/Resources/README.md" ] } }, diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Lectures.pptx b/076-GitHubCopilotCostOptimization/Coach/Lectures.pptx similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Lectures.pptx rename to 076-GitHubCopilotCostOptimization/Coach/Lectures.pptx diff --git a/xxx-GitHubCopilotCostOptimization/Coach/README.md b/076-GitHubCopilotCostOptimization/Coach/README.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/README.md rename to 076-GitHubCopilotCostOptimization/Coach/README.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-00.md b/076-GitHubCopilotCostOptimization/Coach/Solution-00.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solution-00.md rename to 076-GitHubCopilotCostOptimization/Coach/Solution-00.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md b/076-GitHubCopilotCostOptimization/Coach/Solution-01.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solution-01.md rename to 076-GitHubCopilotCostOptimization/Coach/Solution-01.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md b/076-GitHubCopilotCostOptimization/Coach/Solution-02.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solution-02.md rename to 076-GitHubCopilotCostOptimization/Coach/Solution-02.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md b/076-GitHubCopilotCostOptimization/Coach/Solution-03.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solution-03.md rename to 076-GitHubCopilotCostOptimization/Coach/Solution-03.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md b/076-GitHubCopilotCostOptimization/Coach/Solution-04.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solution-04.md rename to 076-GitHubCopilotCostOptimization/Coach/Solution-04.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md b/076-GitHubCopilotCostOptimization/Coach/Solution-05.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solution-05.md rename to 076-GitHubCopilotCostOptimization/Coach/Solution-05.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solution-06.md b/076-GitHubCopilotCostOptimization/Coach/Solution-06.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solution-06.md rename to 076-GitHubCopilotCostOptimization/Coach/Solution-06.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/.gitkeep b/076-GitHubCopilotCostOptimization/Coach/Solutions/.gitkeep similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/.gitkeep rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/.gitkeep diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/copilot-instructions.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/api.instructions.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/instructions/events.instructions.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/.github/skills/free-events-endpoint/SKILL.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/README.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/neighborhoods.ts b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/neighborhoods.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/neighborhoods.ts rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/neighborhoods.ts diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/restaurants.ts b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/restaurants.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/restaurants.ts rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/restaurants.ts diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/events.ts b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/events.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/events.ts rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/events.ts diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/neighborhoods.ts b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/neighborhoods.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/neighborhoods.ts rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/neighborhoods.ts diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/restaurants.ts b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/restaurants.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/restaurants.ts rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/routes/restaurants.ts diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/README.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/harness.py diff --git a/xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md rename to 076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md diff --git a/xxx-GitHubCopilotCostOptimization/README.md b/076-GitHubCopilotCostOptimization/README.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/README.md rename to 076-GitHubCopilotCostOptimization/README.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-00.md b/076-GitHubCopilotCostOptimization/Student/Challenge-00.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Challenge-00.md rename to 076-GitHubCopilotCostOptimization/Student/Challenge-00.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md b/076-GitHubCopilotCostOptimization/Student/Challenge-01.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Challenge-01.md rename to 076-GitHubCopilotCostOptimization/Student/Challenge-01.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md b/076-GitHubCopilotCostOptimization/Student/Challenge-02.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Challenge-02.md rename to 076-GitHubCopilotCostOptimization/Student/Challenge-02.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md b/076-GitHubCopilotCostOptimization/Student/Challenge-03.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Challenge-03.md rename to 076-GitHubCopilotCostOptimization/Student/Challenge-03.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md b/076-GitHubCopilotCostOptimization/Student/Challenge-04.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Challenge-04.md rename to 076-GitHubCopilotCostOptimization/Student/Challenge-04.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md b/076-GitHubCopilotCostOptimization/Student/Challenge-05.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Challenge-05.md rename to 076-GitHubCopilotCostOptimization/Student/Challenge-05.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Challenge-06.md b/076-GitHubCopilotCostOptimization/Student/Challenge-06.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Challenge-06.md rename to 076-GitHubCopilotCostOptimization/Student/Challenge-06.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json b/076-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json similarity index 94% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json rename to 076-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json index 43ee4df62b..bc0dfb3948 100644 --- a/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json +++ b/076-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "name": "xxx-GitHubCopilotCostOptimization", + "name": "076-GitHubCopilotCostOptimization", "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", "hostRequirements": { "cpus": 2 diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/.gitkeep b/076-GitHubCopilotCostOptimization/Student/Resources/.gitkeep similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/.gitkeep rename to 076-GitHubCopilotCostOptimization/Student/Resources/.gitkeep diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/.github/copilot-instructions.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/events.ts diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/neighborhoods.ts b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/neighborhoods.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/neighborhoods.ts rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/neighborhoods.ts diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/restaurants.ts b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/restaurants.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/restaurants.ts rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/data/restaurants.ts diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/events.ts b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/events.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/events.ts rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/events.ts diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/neighborhoods.ts b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/neighborhoods.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/neighborhoods.ts rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/neighborhoods.ts diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/restaurants.ts b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/restaurants.ts similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/restaurants.ts rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/src/routes/restaurants.ts diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/README.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/measurements-template.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/output-constraints.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge-03-ModelSelection/prompts.md diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge06/data/sales.csv b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge06/data/sales.csv similarity index 100% rename from xxx-GitHubCopilotCostOptimization/Student/Resources/Challenge06/data/sales.csv rename to 076-GitHubCopilotCostOptimization/Student/Resources/Challenge06/data/sales.csv From 63cb8fdbaaa44e33a7a57558b6879b0054785467 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Mon, 31 Aug 2026 10:20:05 -0700 Subject: [PATCH 42/48] updating hack number --- .../devcontainer.json | 36 +++++++++++++++++++ .../Resources/.devcontainer/devcontainer.json | 34 ++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 .devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json create mode 100644 xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json diff --git a/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json b/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json new file mode 100644 index 0000000000..84e10376c4 --- /dev/null +++ b/.devcontainer/xxx-GitHubCopilotCostOptimization/devcontainer.json @@ -0,0 +1,36 @@ +{ + "name": "076-GitHubCopilotCostOptimization", + "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", + "workspaceFolder": "/workspace/076-GitHubCopilotCostOptimization/Student/Resources", + "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind,consistency=cached", + "hostRequirements": { + "cpus": 2 + }, + "features": { + "ghcr.io/devcontainers/features/python:1": { "version": "3.12" } + }, + "customizations": { + "vscode": { + "extensions": [ + "github.copilot", + "github.copilot-chat", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] + }, + "codespaces": { + "openFiles": [ + "076-GitHubCopilotCostOptimization/Student/Resources/README.md" + ] + } + }, + "postCreateCommand": "curl -LsSf https://astral.sh/uv/install.sh | sh && ~/.local/bin/uv tool install specify-cli --from git+https://github.com/github/spec-kit.git", + + "forwardPorts": [3000], + "portsAttributes": { + "3000": { + "label": "CityScout NYC App", + "onAutoForward": "notify" + } + } +} diff --git a/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json b/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..bc0dfb3948 --- /dev/null +++ b/xxx-GitHubCopilotCostOptimization/Student/Resources/.devcontainer/devcontainer.json @@ -0,0 +1,34 @@ +{ + "name": "076-GitHubCopilotCostOptimization", + "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", + "hostRequirements": { + "cpus": 2 + }, + "features": { + "ghcr.io/devcontainers/features/python:1": { "version": "3.12" } + }, + "customizations": { + "vscode": { + "extensions": [ + "github.copilot", + "github.copilot-chat", + "dbaeumer.vscode-eslint", + "esbenp.prettier-vscode" + ] + }, + "codespaces": { + "openFiles": [ + "README.md" + ] + } + }, + "postCreateCommand": "curl -LsSf https://astral.sh/uv/install.sh | sh && ~/.local/bin/uv tool install specify-cli --from git+https://github.com/github/spec-kit.git", + + "forwardPorts": [3000], + "portsAttributes": { + "3000": { + "label": "CityScout NYC App", + "onAutoForward": "notify" + } + } +} From a4765a9c723373d68452141b9eeb577ad31e0397 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Mon, 31 Aug 2026 10:36:51 -0700 Subject: [PATCH 43/48] Adding wordlist --- 076-GitHubCopilotCostOptimization/.wordlist.txt | 2 ++ 076-GitHubCopilotCostOptimization/Coach/README.md | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 076-GitHubCopilotCostOptimization/.wordlist.txt diff --git a/076-GitHubCopilotCostOptimization/.wordlist.txt b/076-GitHubCopilotCostOptimization/.wordlist.txt new file mode 100644 index 0000000000..a0a81f4685 --- /dev/null +++ b/076-GitHubCopilotCostOptimization/.wordlist.txt @@ -0,0 +1,2 @@ +UBB +SDD \ No newline at end of file diff --git a/076-GitHubCopilotCostOptimization/Coach/README.md b/076-GitHubCopilotCostOptimization/Coach/README.md index 6483a26ad5..2c259afe92 100644 --- a/076-GitHubCopilotCostOptimization/Coach/README.md +++ b/076-GitHubCopilotCostOptimization/Coach/README.md @@ -59,7 +59,6 @@ Always refer students to the [What The Hack website](https://aka.ms/wth) for the **Prepare measurement tools:** -- Confirm all students have UBB enabled on their GitHub Copilot subscriptions - Verify token visibility in VS Code Output panel (GitHub Copilot Chat) - Test access to GitHub Copilot usage dashboard From 7c76344f0f5dc153a766a36e391ec0d58874feb6 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Mon, 31 Aug 2026 11:25:14 -0700 Subject: [PATCH 44/48] fixing spelling --- .../.wordlist.txt | 21 ++++++++++++++++++- .../Coach/Solution-03.md | 10 ++++----- .../TODO.md | 8 +++---- 3 files changed, 29 insertions(+), 10 deletions(-) diff --git a/076-GitHubCopilotCostOptimization/.wordlist.txt b/076-GitHubCopilotCostOptimization/.wordlist.txt index a0a81f4685..014d05c701 100644 --- a/076-GitHubCopilotCostOptimization/.wordlist.txt +++ b/076-GitHubCopilotCostOptimization/.wordlist.txt @@ -1,2 +1,21 @@ UBB -SDD \ No newline at end of file +SDD +completable +Unoptimized +mathrm +tokenization +backoff +invalidations +subtask +Linters +applyTo +CityScout +runnable +Monotonicity +Andressa +Siqueira +Nefedova +discoverable +checkable +pickleball +breakpoint diff --git a/076-GitHubCopilotCostOptimization/Coach/Solution-03.md b/076-GitHubCopilotCostOptimization/Coach/Solution-03.md index 88431a28ff..455fad835b 100644 --- a/076-GitHubCopilotCostOptimization/Coach/Solution-03.md +++ b/076-GitHubCopilotCostOptimization/Coach/Solution-03.md @@ -60,7 +60,7 @@ Takeaways to draw out: Tell students explicitly: when the base model fails Part 2, **do not coach or retry it** for the measurement. Then have them reason about retries: - *How many base-model attempts would cost more than one premium call?* (Plug in token counts or - your org's multipliers.) + your organizations multipliers.) - *Would any number of attempts reliably get the right answer here?* (No — it's a capability ceiling. This is the key insight: retrying the lower-cost model is throwing good money after bad on tasks it can't reason through.) @@ -79,11 +79,11 @@ base-tier and premium-tier model, paste the two prompts from `Student/Resources/Challenge-03-ModelSelection/prompts.md`, and read tokens from the Output panel / usage view. They fill in `measurements-template.md`. -> Orgs expose different models. Coach students to pick *any* base-tier vs premium-tier pair -> their picker offers — the pattern holds. If your org only exposes one tier, use the coach +> Organizations expose different models. Coach students to pick *any* base-tier vs premium-tier pair +> their picker offers — the pattern holds. If your organization only exposes one tier, use the coach > answer key above as the demonstration, or run the harness live. -> **Token visibility caveat:** depending on Copilot version/org, the Output panel may not show a +> **Token visibility caveat:** depending on Copilot version/organization, the Output panel may not show a > clean per-request token number. If so, students can still observe the *pattern* (premium model > emits much more text). For exact counts, the coach harness (or the GitHub Models playground) > reports `usage.total_tokens` directly. See `TODO.md` — aligning the token-measurement @@ -114,7 +114,7 @@ constraint on a verbose task. recommends walking the large majority of the time. (If a student's base model reliably gets it right, their "base" model may actually be fairly strong — have them drop to the smallest model the picker offers.) -- **Org exposes only one model tier.** Fall back to the answer key, or use the coach harness. +- **Organization exposes only one model tier.** Fall back to the answer key, or use the coach harness. - **Token counts not visible.** Premium model still visibly produces much more text — record the pattern. For exact numbers use the harness. (See token-visibility caveat above.) - **Premium model token counts vary a lot.** Reasoning models have variable hidden token use; diff --git a/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md index 904192ccfe..3d41d65028 100644 --- a/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md +++ b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md @@ -16,7 +16,7 @@ Coach/author notes. The challenge is complete and runnable. This tracks follow-u premium call?" + capability-ceiling point); Part 4 "classify your own tasks"; a "why this matters for coding" paragraph; a token-variance note. - [x] **Output-constraint section** rebuilt around a verbose task (palindrome function, - 190→66 tok on gpt-4.1) — the old version-sort example showed no reduction. + 190→66 tokens on gpt-4.1) — the old version-sort example showed no reduction. ## Open - [ ] **Token-measurement alignment (hack-wide).** The student docs point to @@ -37,10 +37,10 @@ Measured via GitHub Models API (`harness.py`), single-shot, no retries, n=4: | Model | Easy (version sort) | Hard (car wash) | |---|---|---| -| gpt-4.1 (base) | ✅ 4/4, ~106 tok | ❌ 0/4 — says "walk", ~166 tok | -| gpt-5 (premium) | ✅ 4/4, ~293 tok | ✅ 4/4 — says "drive", ~1000 tok | +| gpt-4.1 (base) | ✅ 4/4, ~106 tokens | ❌ 0/4 — says "walk", ~166 tokens | +| gpt-5 (premium) | ✅ 4/4, ~293 tokens | ✅ 4/4 — says "drive", ~1000 tokens | -Output constraint (gpt-4.1, palindrome function): ~190 → ~66 tok = **−65%**, identical code. +Output constraint (gpt-4.1, palindrome function): ~190 → ~66 tokens = **−65%**, identical code. Constraint showed **no** effect on the terse sort task and on gpt-5 (reasoning tokens dominate). Rejected: letter-count/decimal/"strawberry" (tokenization artifacts — don't track price); From b69a594fffd633506f4e30f33f6e5e5d58c434d1 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Mon, 31 Aug 2026 11:32:09 -0700 Subject: [PATCH 45/48] Updating for spellcheck --- 076-GitHubCopilotCostOptimization/.wordlist.txt | 4 ++++ .../Solutions/Challenge-03-ModelSelection-Solutions/TODO.md | 4 ++-- .../Challenge-03-ModelSelection-Solutions/results.md | 2 +- 076-GitHubCopilotCostOptimization/Student/Challenge-05.md | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/076-GitHubCopilotCostOptimization/.wordlist.txt b/076-GitHubCopilotCostOptimization/.wordlist.txt index 014d05c701..fd90ce8fca 100644 --- a/076-GitHubCopilotCostOptimization/.wordlist.txt +++ b/076-GitHubCopilotCostOptimization/.wordlist.txt @@ -19,3 +19,7 @@ discoverable checkable pickleball breakpoint +differentiator +selectable +NYCApp +geolocation \ No newline at end of file diff --git a/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md index 3d41d65028..40187906f9 100644 --- a/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md +++ b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/TODO.md @@ -7,7 +7,7 @@ Coach/author notes. The challenge is complete and runnable. This tracks follow-u to wash my car"). Letter-counting was a tokenization artifact whose results did **not** track price (base model could beat premium — we observed Haiku right / Opus wrong). The car wash tracks capability and is monotonic. See `results.md`. -- [x] **Switched the base/premium pair** to Copilot-pickable models. The old `gpt-4.1-nano` +- [x] **Switched the base/premium pair** to Copilot-selectable models. The old `gpt-4.1-nano` reliably failed the hard task but is **not selectable in the Copilot model picker**, so students couldn't use it. New pair: base `gpt-4.1`, premium `gpt-5`. - [x] **Terminology:** removed "cheap/expensive"; now **base model** / **premium model** @@ -24,7 +24,7 @@ Coach/author notes. The challenge is complete and runnable. This tracks follow-u setup. Verify that Copilot Chat actually surfaces a clean per-request token number in the target VS Code/Copilot version. If it does **not**, this is a **Challenge 00** problem affecting every challenge — fix it there (or standardize on a token source) rather than - only in Challenge 03. Coach harness + GitHub Models playground are reliable fallbacks. + only in Challenge 03. Coach harness + GitHub Models playground are reliable fallback. - [ ] **Advanced section (optional).** Add an "Advanced Challenges" block: try a mid-tier / reasoning model on the hard task (where's the price/capability knee?); build a two-model "base drafts → premium reviews" workflow and measure total cost. diff --git a/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md index b488378bd6..86d6454322 100644 --- a/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md +++ b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-03-ModelSelection-Solutions/results.md @@ -4,7 +4,7 @@ Source: GitHub Models inference API. Method: `harness.py`, **n=4 trials per (mod single-shot (no retries). Exact token counts vary by model version; the **pattern is stable.** Models used as the demonstration pair: -- **Base:** `openai/gpt-4.1` (included tier, no premium multiplier — pickable in Copilot Chat) +- **Base:** `openai/gpt-4.1` (included tier, no premium multiplier — selectable in Copilot Chat) - **Premium:** `openai/gpt-5` (frontier/reasoning tier) ## Summary diff --git a/076-GitHubCopilotCostOptimization/Student/Challenge-05.md b/076-GitHubCopilotCostOptimization/Student/Challenge-05.md index 7232f3c8fd..37c82ca05d 100644 --- a/076-GitHubCopilotCostOptimization/Student/Challenge-05.md +++ b/076-GitHubCopilotCostOptimization/Student/Challenge-05.md @@ -24,7 +24,7 @@ Using the NYC App you worked with in Challenge 02 (in `Resources/Challenge-02-NY - **Feature 1 – Restaurant Filtering:** Add query-parameter support to `GET /restaurants` so callers can filter by `borough` and/or `cuisine` (e.g., `/restaurants?borough=Brooklyn&cuisine=Mexican`). Return the full list when no filters are provided. - **Feature 2 – Neighborhood Detail with Restaurants:** Add `GET /neighborhoods/:name` that returns the matching neighborhood object plus an embedded array of restaurants in that neighborhood (a cross-file join between `neighborhoods.ts` and `restaurants.ts` data). - **Feature 3 – Pagination (cross-cutting):** Add `?page=N&limit=N` support to all three list endpoints (`/events/free-this-week`, `/restaurants`, `/neighborhoods`). Default to page 1, limit 10. Return `{ page, limit, total, data }`. -- **Feature 4 – Input Validation & Error Handling:** Add proper `400 Bad Request` responses for invalid query params and `404 Not Found` for missing resources across all routes. +- **Feature 4 – Input Validation & Error Handling:** Add proper `400 Bad Request` responses for invalid query parameters and `404 Not Found` for missing resources across all routes. These four features touch multiple files, require cross-file references, and create natural breakpoints between each feature—ideal for testing context management strategies. We recommend not committing these files to make it easier to revert. From 84c2141a53fa14e956ea553757188176fd83db51 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Mon, 31 Aug 2026 11:37:52 -0700 Subject: [PATCH 46/48] Update .wordlist.txt --- 076-GitHubCopilotCostOptimization/.wordlist.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/076-GitHubCopilotCostOptimization/.wordlist.txt b/076-GitHubCopilotCostOptimization/.wordlist.txt index fd90ce8fca..1512ace165 100644 --- a/076-GitHubCopilotCostOptimization/.wordlist.txt +++ b/076-GitHubCopilotCostOptimization/.wordlist.txt @@ -22,4 +22,11 @@ breakpoint differentiator selectable NYCApp -geolocation \ No newline at end of file +geolocation +unmanaged +useEffect +useState +YYYY +priceLevel +bestFor +walkability \ No newline at end of file From 958e973d56ac53db452202cc97746f1b8221eda3 Mon Sep 17 00:00:00 2001 From: Andy Huang <54148527+Whowong@users.noreply.github.com> Date: Mon, 31 Aug 2026 12:25:43 -0700 Subject: [PATCH 47/48] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../Student/Resources/Challenge-02-NYCApp/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md index 5cb8a00852..87ba71fab4 100644 --- a/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md +++ b/076-GitHubCopilotCostOptimization/Student/Resources/Challenge-02-NYCApp/README.md @@ -1,5 +1,5 @@ -# CityScout NYC - Challenge 01 Starter (FULL VERSION) +# CityScout NYC - Challenge 02 Starter (FULL VERSION) ## ✅ WHERE YOU SHOULD MAKE CHANGES From 4dc1ce65450983ab2830629919a43009c6a97e78 Mon Sep 17 00:00:00 2001 From: Devanshi Thakar <33441411+devanshithakar12@users.noreply.github.com> Date: Mon, 31 Aug 2026 16:55:37 -0400 Subject: [PATCH 48/48] Fix for keeping the events updated Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../Challenge-02-NYCApp-Solutions/src/data/events.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts index 44040e6bd4..cbccf0bfab 100644 --- a/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts +++ b/076-GitHubCopilotCostOptimization/Coach/Solutions/Challenge-02-NYCApp-Solutions/src/data/events.ts @@ -1,7 +1,9 @@ +const dateFromToday = (offsetDays: number) => + new Date(Date.now() + offsetDays * 86_400_000).toISOString().slice(0, 10); export const events = [ - { name: 'Central Park Yoga', date: '2026-06-30', price: 0 }, - { name: 'Brooklyn Flea Market Walk', date: '2026-07-01', price: 0 }, - { name: 'Rooftop Movie Night', date: '2026-07-02', price: 15 }, - { name: 'Jazz in Washington Square Park', date: '2026-07-10', price: 0 } + { name: 'Central Park Yoga', date: dateFromToday(1), price: 0 }, + { name: 'Brooklyn Flea Market Walk', date: dateFromToday(2), price: 0 }, + { name: 'Rooftop Movie Night', date: dateFromToday(3), price: 15 }, + { name: 'Jazz in Washington Square Park', date: dateFromToday(10), price: 0 } ];