Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 23 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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/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 }})
Expand Down Expand Up @@ -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"
87 changes: 87 additions & 0 deletions plugins/corbits-skills/skills/create-issue/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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-name> product"

Project: Get 10 customer leads for <product-name> through direct outreach
Lead: <to be assigned>
Target: 2 weeks
Description:
Hypothesis - Teams we know and can reach out to have a need for <product-name>.

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 <product-name> 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: <executive-owner>
Target: <target-quarter>

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?
```
47 changes: 36 additions & 11 deletions tests/unit/check-gate.test.ts
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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),
);
});
});
Loading