From fed0cab20c6221a2b6c6d4acc5427ecaae460223 Mon Sep 17 00:00:00 2001 From: Kurt Overmier Date: Fri, 12 Jun 2026 07:04:40 -0500 Subject: [PATCH 1/2] feat(scaffold-core@1.1.0): workers-saas pattern + LocalScaffoldResult fields (#221) - Add 'workers-saas' to PatternName union; SaaS Signal pattern now emits this name directly (was 'worker') for multi-tenant/org/workspace/saas intentions - LocalScaffoldResult gains `traits: string[]` (promoted from classification.traits) and `tier2Recommended: boolean` (classification.confidence < 0.6) - Tests updated to assert result.pattern === 'workers-saas' for multi-tenant intentions; 738/738 tests green Closes #221 Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 9 +++++++++ packages/scaffold-core/package.json | 2 +- .../scaffold-core/src/__tests__/classify.test.ts | 3 ++- packages/scaffold-core/src/__tests__/types.test.ts | 12 ++++++++++++ packages/scaffold-core/src/classify/patterns.ts | 2 +- packages/scaffold-core/src/index.ts | 2 ++ packages/scaffold-core/src/types.ts | 5 +++++ 7 files changed, 32 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e211f2d..6007430 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ The format is based on Keep a Changelog and follows Semantic Versioning. ## [Unreleased] +## [@stackbilt/scaffold-core@1.1.0] — 2026-06-12 + +### Changed +- `PatternName` now includes `'workers-saas'` — multi-tenant SaaS intentions classify to this pattern (previously returned `'worker'`) +- `LocalScaffoldResult` gains two new fields: `traits: string[]` (promoted from `classification.traits`) and `tier2Recommended: boolean` (true when confidence < 0.6) +- `classify.test.ts` updated to assert `result.pattern === 'workers-saas'` for multi-tenant intentions + +Closes charter#221 + ### Added - **`charter score --badge`** (`score.ts`): New output mode that prints a [shields.io endpoint-schema](https://shields.io/badges/endpoint-badge) JSON payload to stdout (`{"schemaVersion":1,"label":"agent context","message":"A (92)","color":"brightgreen"}`). Grade-to-color mapping: A=brightgreen, B=green, C=yellowgreen, D=yellow, F=red. Combine with `--badge --write` to persist the payload to `.charter/badge.json` so it can be served via `raw.githubusercontent.com` as a live shields.io endpoint badge. Additive only — no existing flag, output, or exit-code behavior is changed. Exports `buildBadgePayload`, `gradeToColor`, and the `BadgePayload` type for downstream use. diff --git a/packages/scaffold-core/package.json b/packages/scaffold-core/package.json index 7b76163..fda103e 100644 --- a/packages/scaffold-core/package.json +++ b/packages/scaffold-core/package.json @@ -1,7 +1,7 @@ { "name": "@stackbilt/scaffold-core", "sideEffects": false, - "version": "1.0.0", + "version": "1.1.0", "description": "Zero-dependency scaffold engine core — pattern classification, knowledge, governance, codegen, and materializer", "main": "./dist/index.js", "types": "./dist/index.d.ts", diff --git a/packages/scaffold-core/src/__tests__/classify.test.ts b/packages/scaffold-core/src/__tests__/classify.test.ts index 299b3a1..004d625 100644 --- a/packages/scaffold-core/src/__tests__/classify.test.ts +++ b/packages/scaffold-core/src/__tests__/classify.test.ts @@ -37,7 +37,7 @@ function sourcePattern(result: LocalScaffoldResult): string { describe('scaffold domain fixtures — tenancy guardrail (#177)', () => { it('recognizes multi-tenant SaaS with org isolation as workers-saas pattern', () => { const result = classify('Multi-tenant SaaS API with organization-level data isolation'); - // workers-saas maps to jwt-auth trait + rest route shape in the package + expect(result.pattern).toBe('workers-saas'); expect(result.traits).toContain('jwt-auth'); }); @@ -50,6 +50,7 @@ describe('scaffold domain fixtures — tenancy guardrail (#177)', () => { it('recognizes tenant isolation with row-level security as workers-saas', () => { const result = classify('Tenant isolation API with row-level security in D1'); + expect(result.pattern).toBe('workers-saas'); expect(result.traits).toContain('jwt-auth'); }); }); diff --git a/packages/scaffold-core/src/__tests__/types.test.ts b/packages/scaffold-core/src/__tests__/types.test.ts index e589eb1..3a1e16b 100644 --- a/packages/scaffold-core/src/__tests__/types.test.ts +++ b/packages/scaffold-core/src/__tests__/types.test.ts @@ -73,6 +73,18 @@ describe('classify and buildScaffold are implemented', () => { expect(result.files).toBeDefined(); }); + it('buildScaffold promotes traits and tier2Recommended to top-level', () => { + const result = buildScaffold('multi-tenant SaaS API with JWT auth'); + expect(Array.isArray(result.traits)).toBe(true); + expect(typeof result.tier2Recommended).toBe('boolean'); + expect(result.traits).toEqual(result.classification.traits); + }); + + it('workers-saas pattern is assignable as PatternName', () => { + const p: PatternName = 'workers-saas'; + expect(p).toBe('workers-saas'); + }); + it('classify returns a ClassifyResult without throwing', () => { const result = classify('build a KV-backed worker'); expect(result).toBeDefined(); diff --git a/packages/scaffold-core/src/classify/patterns.ts b/packages/scaffold-core/src/classify/patterns.ts index 32d450b..df8edac 100644 --- a/packages/scaffold-core/src/classify/patterns.ts +++ b/packages/scaffold-core/src/classify/patterns.ts @@ -121,7 +121,7 @@ export const SCORED_PATTERNS: ScoredPatternDef[] = [ }, }, { - name: 'worker' as PatternName, + name: 'workers-saas' as PatternName, status: 'ACTIVE', category: 'COMPUTE', keywords: ['saas', 'tenant', 'multi-tenant', 'org', 'workspace'], diff --git a/packages/scaffold-core/src/index.ts b/packages/scaffold-core/src/index.ts index 9d45567..602385e 100644 --- a/packages/scaffold-core/src/index.ts +++ b/packages/scaffold-core/src/index.ts @@ -123,5 +123,7 @@ export function buildScaffold( governance, files: finalFiles, facts, + traits: classification.traits, + tier2Recommended: classification.confidence < 0.6, }; } diff --git a/packages/scaffold-core/src/types.ts b/packages/scaffold-core/src/types.ts index 1ff3a54..467e8de 100644 --- a/packages/scaffold-core/src/types.ts +++ b/packages/scaffold-core/src/types.ts @@ -11,6 +11,7 @@ export type PatternName = | 'worker' + | 'workers-saas' | 'api' | 'fullstack' | 'scheduled' @@ -132,6 +133,10 @@ export interface LocalScaffoldResult { governance: GovernanceDocs; files: ScaffoldFile[]; facts: ScaffoldFacts; + /** Promoted from classification.traits for convenient top-level access */ + traits: string[]; + /** True when classifier confidence is below 0.6 — signals LLM tier-2 may improve results */ + tier2Recommended: boolean; } export interface ScaffoldOptions { From 2b7c887957a49d116ef77a5d29cffb8bb3cb190c Mon Sep 17 00:00:00 2001 From: Kurt Overmier Date: Fri, 12 Jun 2026 07:08:19 -0500 Subject: [PATCH 2/2] fix(scaffold-core): update version assertion to 1.1.0 Co-Authored-By: Claude Sonnet 4.6 --- packages/scaffold-core/src/__tests__/package.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/scaffold-core/src/__tests__/package.test.ts b/packages/scaffold-core/src/__tests__/package.test.ts index 04836e5..0052fbc 100644 --- a/packages/scaffold-core/src/__tests__/package.test.ts +++ b/packages/scaffold-core/src/__tests__/package.test.ts @@ -12,8 +12,8 @@ describe('@stackbilt/scaffold-core package metadata', () => { expect(pkg.name).toBe('@stackbilt/scaffold-core'); }); - it('version is 1.0.0', () => { - expect(pkg.version).toBe('1.0.0'); + it('version is 1.1.0', () => { + expect(pkg.version).toBe('1.1.0'); }); it('license is Apache-2.0', () => {