From 2880f9a8c3f8ca32359f5aacd9e508a3c9705388 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sun, 13 Sep 2026 13:06:35 -0700 Subject: [PATCH 1/4] Shard the src CI leg into three balanced matrix legs The single test (src) leg ran ~92s warm and set the CI wall clock. Three path-disjoint shards (tui; agent+subagent; everything else) run ~30/46/45s locally, and a test (src) dummy preserves the required check name once every leg passes. --- .github/workflows/ci.yml | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b38006e1..296774c28 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,19 +78,28 @@ jobs: run: bun run build # The suite is sharded so the slowest slice, not the whole suite, sets the - # wall clock. Every shard still goes through check:projects-dir-guard: the + # wall clock. The old ./src leg (387 files, ~88s local) is split into three + # path-disjoint shards measured at ~30s (src-a: tui, 146 files), ~46s + # (src-b: agent + subagent, 90 files), and ~45s (src-c: everything else in + # src, 153 files); the ./tests leg stays whole because ./evals ./scripts + # finish in ~1s and a leg of their own would be all setup overhead. + # Every shard still goes through check:projects-dir-guard: the # guard forwards these path filters to the suite it wraps, and the union of # the shards' filters is exactly ./src ./tests ./evals ./scripts, so the gate covers # the same tests as before, all of them sandboxed. test: runs-on: ubuntu-latest strategy: - # A red shard must not cancel the other; both results are the signal. + # A red shard must not cancel the others; every result is the signal. fail-fast: false matrix: shard: - - name: src - paths: ./src + - name: src-a + paths: ./src/tui + - name: src-b + paths: ./src/agent ./src/subagent + - name: src-c + paths: ./src/auth ./src/changelog ./src/config ./src/cost ./src/crash ./src/logging ./src/mcp ./src/perf ./src/permission ./src/plugins ./src/provider ./src/session ./src/shell ./src/telemetry ./src/tools ./src/trust ./src/upgrade ./src/util ./src/web ./src/config.test.ts ./src/context-compactor.test.ts ./src/director.test.ts ./src/inference-abort.test.ts ./src/inference-error-message.test.ts ./src/inference-gateway-error.test.ts ./src/list-dir.test.ts ./src/pricing-fetcher.test.ts ./src/pricing-metadata.test.ts ./src/profiles.test.ts ./src/prompts.test.ts ./src/renderer.test.ts ./src/settings.test.ts ./src/state.test.ts - name: tests-evals-and-scripts paths: ./tests ./evals ./scripts name: test (${{ matrix.shard.name }}) @@ -161,3 +170,13 @@ jobs: runs-on: ubuntu-latest steps: - run: "true" + + # The src-a/src-b/src-c matrix legs replaced the single test (src) leg, so + # this publishes that context name once all legs pass. needs: test waits for + # every matrix leg; a red leg skips this instead of greening it. + test-src: + name: test (src) + needs: test + runs-on: ubuntu-latest + steps: + - run: "true" From b44581a11b268e76947d439cc0d376484fe055d1 Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sun, 13 Sep 2026 13:12:57 -0700 Subject: [PATCH 2/4] Check CI shard coverage as a file set, not a path string Subdirectory shards (src-a/b/c) can never equal the literal ./src filter string, so the gate now expands both sides to test files. Sorted-array equality still fails on a dropped file or a file covered twice. --- tests/unit/check-gate.test.ts | 47 +++++++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/tests/unit/check-gate.test.ts b/tests/unit/check-gate.test.ts index 73018d997..882e22c9f 100644 --- a/tests/unit/check-gate.test.ts +++ b/tests/unit/check-gate.test.ts @@ -1,5 +1,5 @@ -import { readFileSync } from "node:fs"; -import { join } from "node:path"; +import { readdirSync, readFileSync, statSync } from "node:fs"; +import { join, relative } from "node:path"; import { describe, expect, test } from "bun:test"; // Guard against the gate drifting apart again (CL-7300): `bun run check` and @@ -27,6 +27,25 @@ const GUARD_SCRIPT = "check:projects-dir-guard"; const TEST_SUITE = "bun test ./src ./tests ./evals ./scripts --randomize --seed 424242"; +function expandToTestFiles(filters: string[]): string[] { + const files: string[] = []; + const walk = (dir: string) => { + for (const entry of readdirSync(dir, { withFileTypes: true })) { + const absolute = join(dir, entry.name); + if (entry.isDirectory()) walk(absolute); + else if (entry.name.endsWith(".test.ts")) + files.push(relative(repoRoot, absolute).split("/").join("/")); + } + }; + for (const filter of filters) { + const absolute = join(repoRoot, filter.replace(/^\.\//, "")); + if (statSync(absolute).isFile()) + files.push(relative(repoRoot, absolute).split("/").join("/")); + else walk(absolute); + } + return files.sort(); +} + describe("check gate", () => { test("`test` is the seeded, randomized one-process suite whose path union CI shards", () => { expect(pkg.scripts.test).toBe(TEST_SUITE); @@ -67,14 +86,20 @@ describe("check gate", () => { }); test("CI test shards cover exactly the suite's paths", () => { - // Sharding must never silently drop part of the suite: the union of the - // matrix shards has to equal the unsharded `test` script's paths. - const shardPaths = [...ci.matchAll(/^\s+paths: (.+)$/gm)] - .flatMap((match) => match[1]?.trim().split(/\s+/) ?? []) - .sort(); - const suitePaths = TEST_SUITE.split(" ") - .filter((part) => part.startsWith("./")) - .sort(); - expect(shardPaths).toEqual(suitePaths); + // Sharding must never silently drop (or double-run) part of the suite: + // expanding the matrix shards' filters to test files has to equal the + // unsharded `test` script's paths expanded the same way. Subdirectory + // shards (src-a/b/c) can never equal the literal ./src string, so this + // compares sorted file sets; a file covered twice fails the equality + // through the duplicate entry. + const shardFilters = [...ci.matchAll(/^\s+paths: (.+)$/gm)].flatMap( + (match) => match[1]?.trim().split(/\s+/) ?? [], + ); + const suiteFilters = TEST_SUITE.split(" ").filter((part) => + part.startsWith("./"), + ); + expect(expandToTestFiles(shardFilters)).toEqual( + expandToTestFiles(suiteFilters), + ); }); }); From 9d5ba1f8382e59f644ec4c64d9fba70d1536d51f Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sun, 13 Sep 2026 13:27:08 -0700 Subject: [PATCH 3/4] docs(skills): restore missing Common Patterns in create-issue skill Port Validation Project, Strategic Goal to Initiative, and Planning Document to Issues verbatim from gaas linear-create. Closes CL-7926. --- .../skills/create-issue/SKILL.md | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/plugins/corbits-skills/skills/create-issue/SKILL.md b/plugins/corbits-skills/skills/create-issue/SKILL.md index 3a484bfbd..fc42b94ae 100644 --- a/plugins/corbits-skills/skills/create-issue/SKILL.md +++ b/plugins/corbits-skills/skills/create-issue/SKILL.md @@ -388,3 +388,90 @@ Issues: 4. "Add theme persistence to user preferences" - Blocked by: #1 ``` + +### Validation Project + +``` +User: "We need to validate if customers want our new product" + +Project: Get 10 customer leads for through direct outreach + Lead: + Target: 2 weeks + Description: + Hypothesis - Teams we know and can reach out to have a need for . + + Experiment + Direct Outreach + + - [ ] Create list of targets + - [ ] Create collateral if needed + - [ ] Create strategy for outreach including any templates + - [ ] Execute outreach + - [ ] Conduct customer interviews + - [ ] Analyze results + + Milestones: + 1. Target list and collateral ready + 2. Outreach completed + 3. Customer interviews recorded + 4. Analysis complete + +Issues: + 1. "Create target list for outreach" + 2. "Create outreach collateral and templates" + 3. "Execute outreach campaign" + - Blocked by: #1, #2 + 4. "Conduct and record customer interviews" + - Blocked by: #3 + 5. "Analyze results and present findings" + - Blocked by: #4 +``` + +### Strategic Goal to Initiative + +``` +User: "We need to expand our platform to support enterprise customers" + +Initiative: Enterprise platform expansion + Owner: + Target: + +Projects: + 1. "Multi-tenant architecture" - Isolate customer data and resources + 2. "Enterprise SSO integration" - Support SAML and OIDC providers + 3. "Admin dashboard" - Self-service management for enterprise admins + 4. "Audit logging" - Compliance-ready activity tracking +``` + +### Planning Document to Issues + +``` +User: "Create issues from our product doc" or "--from-doc" + +[Skill searches for PRODUCT.md, ARCHITECTURE.md, IMPLEMENTATION.md] +[Finds PRODUCT.md with feature descriptions] + +Skill: I found PRODUCT.md which describes the following features: + - User authentication with SSO + - Usage metrics dashboard + - Export functionality + +Based on the document, I propose: + +**Project**: User authentication with SSO support + (From PRODUCT.md: "Users need secure login with enterprise SSO...") + +**Issues**: + 1. "Implement basic email/password authentication" + # Background + From PRODUCT.md: Users need secure login... + + # Outcome + - [ ] Users can register with email/password + - [ ] Users can log in and log out + + 2. "Integrate SAML SSO provider" + ... + +Which features would you like me to create issues for? +``` From 823f20d64552d8cb5775cefac0b3f2606264000e Mon Sep 17 00:00:00 2001 From: Sawyer Cutler Date: Sun, 13 Sep 2026 23:17:35 -0700 Subject: [PATCH 4/4] Cover the new src/exec directory in the src-c CI shard --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 296774c28..fdf61e657 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -99,7 +99,7 @@ jobs: - name: src-b paths: ./src/agent ./src/subagent - name: src-c - paths: ./src/auth ./src/changelog ./src/config ./src/cost ./src/crash ./src/logging ./src/mcp ./src/perf ./src/permission ./src/plugins ./src/provider ./src/session ./src/shell ./src/telemetry ./src/tools ./src/trust ./src/upgrade ./src/util ./src/web ./src/config.test.ts ./src/context-compactor.test.ts ./src/director.test.ts ./src/inference-abort.test.ts ./src/inference-error-message.test.ts ./src/inference-gateway-error.test.ts ./src/list-dir.test.ts ./src/pricing-fetcher.test.ts ./src/pricing-metadata.test.ts ./src/profiles.test.ts ./src/prompts.test.ts ./src/renderer.test.ts ./src/settings.test.ts ./src/state.test.ts + paths: ./src/auth ./src/changelog ./src/config ./src/cost ./src/crash ./src/exec ./src/logging ./src/mcp ./src/perf ./src/permission ./src/plugins ./src/provider ./src/session ./src/shell ./src/telemetry ./src/tools ./src/trust ./src/upgrade ./src/util ./src/web ./src/config.test.ts ./src/context-compactor.test.ts ./src/director.test.ts ./src/inference-abort.test.ts ./src/inference-error-message.test.ts ./src/inference-gateway-error.test.ts ./src/list-dir.test.ts ./src/pricing-fetcher.test.ts ./src/pricing-metadata.test.ts ./src/profiles.test.ts ./src/prompts.test.ts ./src/renderer.test.ts ./src/settings.test.ts ./src/state.test.ts - name: tests-evals-and-scripts paths: ./tests ./evals ./scripts name: test (${{ matrix.shard.name }})