@sun-asterisk/sungen 3.1.2-beta.121 → 3.1.2-beta.123
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities/context.d.ts +17 -0
- package/dist/capabilities/context.d.ts.map +1 -1
- package/dist/capabilities/registry.d.ts +3 -1
- package/dist/capabilities/registry.d.ts.map +1 -1
- package/dist/capabilities/registry.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +2 -1
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/context.d.ts.map +1 -1
- package/dist/cli/commands/context.js +2 -1
- package/dist/cli/commands/context.js.map +1 -1
- package/dist/cli/commands/delivery.d.ts.map +1 -1
- package/dist/cli/commands/delivery.js +13 -1
- package/dist/cli/commands/delivery.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +2 -1
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/ledger.d.ts.map +1 -1
- package/dist/cli/commands/ledger.js +4 -2
- package/dist/cli/commands/ledger.js.map +1 -1
- package/dist/cli/commands/manifest.d.ts.map +1 -1
- package/dist/cli/commands/manifest.js +2 -1
- package/dist/cli/commands/manifest.js.map +1 -1
- package/dist/cli/commands/repair.d.ts +8 -0
- package/dist/cli/commands/repair.d.ts.map +1 -0
- package/dist/cli/commands/repair.js +97 -0
- package/dist/cli/commands/repair.js.map +1 -0
- package/dist/cli/commands/script-check.d.ts.map +1 -1
- package/dist/cli/commands/script-check.js +2 -1
- package/dist/cli/commands/script-check.js.map +1 -1
- package/dist/cli/commands/trace.d.ts.map +1 -1
- package/dist/cli/commands/trace.js +2 -1
- package/dist/cli/commands/trace.js.map +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/harness/repair.d.ts +20 -0
- package/dist/harness/repair.d.ts.map +1 -0
- package/dist/harness/repair.js +111 -0
- package/dist/harness/repair.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +1 -1
- package/dist/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +3 -3
- package/dist/orchestrator/templates/ai-instructions/claude-skill-api-design.md +4 -4
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +1 -1
- package/dist/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +3 -3
- package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-api-design.md +4 -4
- package/package.json +2 -2
- package/src/capabilities/context.ts +19 -0
- package/src/capabilities/registry.ts +3 -1
- package/src/cli/commands/audit.ts +2 -1
- package/src/cli/commands/context.ts +3 -2
- package/src/cli/commands/delivery.ts +11 -1
- package/src/cli/commands/generate.ts +2 -1
- package/src/cli/commands/ledger.ts +4 -2
- package/src/cli/commands/manifest.ts +2 -1
- package/src/cli/commands/repair.ts +57 -0
- package/src/cli/commands/script-check.ts +2 -1
- package/src/cli/commands/trace.ts +2 -1
- package/src/cli/index.ts +2 -0
- package/src/harness/repair.ts +75 -0
- package/src/index.ts +1 -1
- package/src/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +1 -1
- package/src/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +3 -3
- package/src/orchestrator/templates/ai-instructions/claude-skill-api-design.md +4 -4
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +1 -1
- package/src/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +3 -3
- package/src/orchestrator/templates/ai-instructions/github-skill-sungen-api-design.md +4 -4
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { planRepair } from '../../harness/repair';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* `sungen repair` (#343) — turn a unit's audit findings + Playwright failures into a concrete fix
|
|
8
|
+
* plan, using the unit-capability's fix catalog (the `repair` SPI). Deterministic; the `/sungen:design`
|
|
9
|
+
* + `/sungen:run-test` repair loops apply the same proposals. Run `sungen audit`/the tests first.
|
|
10
|
+
*/
|
|
11
|
+
export function registerRepairCommand(program: Command): void {
|
|
12
|
+
program
|
|
13
|
+
.command('repair')
|
|
14
|
+
.description('Propose concrete fixes for a unit from its audit findings + test failures (capability fix catalog)')
|
|
15
|
+
.option('-s, --screen <name>', 'Screen or flow name')
|
|
16
|
+
.option('--api <name>', 'API-first area or api flow (qa/api/<name>)')
|
|
17
|
+
.option('--area <name>', 'Alias of --api — an API-first area (qa/api/<name>)')
|
|
18
|
+
.option('--json', 'Output raw JSON')
|
|
19
|
+
.action((o: { screen?: string; api?: string; area?: string; json?: boolean }) => {
|
|
20
|
+
try {
|
|
21
|
+
const name = o.screen || o.api || o.area;
|
|
22
|
+
if (!name) throw new Error('Provide --screen <name> (or --api <area>)');
|
|
23
|
+
const cwd = process.cwd();
|
|
24
|
+
// Capability-resolution id + the generated dir, per kind.
|
|
25
|
+
const kind = fs.existsSync(path.join(cwd, 'qa', 'api', name)) || o.api ? 'api'
|
|
26
|
+
: fs.existsSync(path.join(cwd, 'qa', 'flows', name)) ? 'flow' : 'screen';
|
|
27
|
+
const unitId = kind === 'api' ? `api/${name}` : kind === 'flow' ? `flows/${name}` : name;
|
|
28
|
+
const generatedDir = path.join(cwd, 'specs', 'generated', kind === 'api' ? path.join('api', name) : kind === 'flow' ? path.join('flows', name) : name);
|
|
29
|
+
|
|
30
|
+
const plan = planRepair(unitId, name, cwd, generatedDir);
|
|
31
|
+
if (o.json) { console.log(JSON.stringify(plan, null, 2)); return; }
|
|
32
|
+
|
|
33
|
+
const L = console.log;
|
|
34
|
+
L(`\n━━━ Repair plan: ${name} (capability: ${plan.capability ?? 'none'}) ━━━`);
|
|
35
|
+
if (!plan.rulesAvailable) L(` (this capability ships no repair rules)`);
|
|
36
|
+
if (!plan.proposals.length && !plan.unmatched.length) {
|
|
37
|
+
L(` ✓ Nothing to repair — run \`sungen audit --${kind === 'api' ? 'api' : 'screen'} ${name}\` + the tests first, or the unit is clean.\n`);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (plan.proposals.length) {
|
|
41
|
+
L(`\n Proposed fixes (${plan.proposals.length}):`);
|
|
42
|
+
for (const p of plan.proposals) {
|
|
43
|
+
L(` • [${p.ruleId}] ${p.source === 'runtime' ? '(test) ' : ''}${p.signal}`);
|
|
44
|
+
L(` → ${p.fix}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (plan.unmatched.length) {
|
|
48
|
+
L(`\n No known rule (review manually):`);
|
|
49
|
+
for (const u of plan.unmatched.slice(0, 10)) L(` - ${u}`);
|
|
50
|
+
}
|
|
51
|
+
L('');
|
|
52
|
+
} catch (e) {
|
|
53
|
+
console.error('Error:', e instanceof Error ? e.message : e);
|
|
54
|
+
process.exit(1);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
@@ -9,10 +9,11 @@ export function registerScriptCheckCommand(program: Command): void {
|
|
|
9
9
|
.description('Verify the generated Playwright spec is a faithful 1:1 of the Gherkin feature (no hand-edit / stale drift)')
|
|
10
10
|
.option('-s, --screen <name>', 'Screen or flow name')
|
|
11
11
|
.option('--api <name>', 'API-first area or api flow (qa/api/<name>)')
|
|
12
|
+
.option('--area <name>', 'Alias of --api — an API-first area (qa/api/<name>)')
|
|
12
13
|
.option('--json', 'Output raw JSON')
|
|
13
14
|
.action(async (options) => {
|
|
14
15
|
try {
|
|
15
|
-
const name = options.screen || options.api;
|
|
16
|
+
const name = options.screen || options.api || options.area;
|
|
16
17
|
if (!name) throw new Error('Provide --screen <name> (or --api <area>)');
|
|
17
18
|
const screen = path.join(process.cwd(), 'qa', 'screens', name);
|
|
18
19
|
const flow = path.join(process.cwd(), 'qa', 'flows', name);
|
|
@@ -9,11 +9,12 @@ export function registerTraceCommand(program: Command): void {
|
|
|
9
9
|
.description('Visualise the executed test-design process (workflow/skill steps, repair loops), find bottlenecks, and show where to focus human review')
|
|
10
10
|
.option('-s, --screen <name>', 'Screen or flow name')
|
|
11
11
|
.option('--api <name>', 'API-first area or api flow (qa/api/<name>)')
|
|
12
|
+
.option('--area <name>', 'Alias of --api — an API-first area (qa/api/<name>)')
|
|
12
13
|
.option('--json', 'Output raw JSON')
|
|
13
14
|
.option('--mermaid', 'Print only the Mermaid flowchart')
|
|
14
15
|
.action((options) => {
|
|
15
16
|
try {
|
|
16
|
-
const name = options.screen || options.api;
|
|
17
|
+
const name = options.screen || options.api || options.area;
|
|
17
18
|
if (!name) throw new Error('Provide --screen <name> (or --api <area>)');
|
|
18
19
|
const screen = path.join(process.cwd(), 'qa', 'screens', name);
|
|
19
20
|
const flow = path.join(process.cwd(), 'qa', 'flows', name);
|
package/src/cli/index.ts
CHANGED
|
@@ -27,6 +27,7 @@ import { registerBlindspotCommand } from './commands/blindspot';
|
|
|
27
27
|
import { registerCapabilityCommand } from './commands/capability';
|
|
28
28
|
import { registerFlowCheckCommand } from './commands/flow-check';
|
|
29
29
|
import { registerContextCommand } from './commands/context';
|
|
30
|
+
import { registerRepairCommand } from './commands/repair';
|
|
30
31
|
import { capabilityRegistry } from '../capabilities/registry';
|
|
31
32
|
import { discoverAndRegisterCapabilities } from '../capabilities/discover';
|
|
32
33
|
|
|
@@ -66,6 +67,7 @@ async function main() {
|
|
|
66
67
|
registerCapabilityCommand(program);
|
|
67
68
|
registerFlowCheckCommand(program);
|
|
68
69
|
registerContextCommand(program);
|
|
70
|
+
registerRepairCommand(program);
|
|
69
71
|
registerIngestCommand(program);
|
|
70
72
|
registerEvalCommand(program);
|
|
71
73
|
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repair planner (#343) — the consumer of the `repair` capability SPI.
|
|
3
|
+
*
|
|
4
|
+
* Gathers the unit-capability's fix rules and matches them against the audit findings (always) and
|
|
5
|
+
* the latest Playwright failures (best-effort), turning them into a concrete fix plan. Deterministic:
|
|
6
|
+
* the AI repair loop and a human get the same proposals. Backs `sungen repair`.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from 'fs';
|
|
9
|
+
import * as path from 'path';
|
|
10
|
+
import { capabilityRegistry } from '../capabilities/registry';
|
|
11
|
+
import { discoverAndRegisterCapabilities } from '../capabilities/discover';
|
|
12
|
+
import { scoringCapabilityFor } from './audit';
|
|
13
|
+
|
|
14
|
+
export interface RepairProposal { source: 'audit' | 'runtime'; signal: string; ruleId: string; fix: string }
|
|
15
|
+
export interface RepairPlan {
|
|
16
|
+
capability: string | undefined;
|
|
17
|
+
rulesAvailable: number;
|
|
18
|
+
proposals: RepairProposal[];
|
|
19
|
+
unmatched: string[]; // findings/failures with no matching rule (need a human)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Collect failure messages from a Playwright JSON result file (best-effort, defensive). */
|
|
23
|
+
function failuresFromResult(file: string): string[] {
|
|
24
|
+
const out: string[] = [];
|
|
25
|
+
try {
|
|
26
|
+
const r = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
27
|
+
const visit = (suite: any) => {
|
|
28
|
+
for (const sp of suite.specs ?? []) {
|
|
29
|
+
for (const t of sp.tests ?? []) {
|
|
30
|
+
for (const res of t.results ?? []) {
|
|
31
|
+
if (res.status === 'failed' || res.status === 'timedOut') {
|
|
32
|
+
const msg = res.error?.message || res.errors?.[0]?.message || res.status;
|
|
33
|
+
out.push(`${sp.title}: ${String(msg).split('\n')[0].slice(0, 200)}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
for (const s of suite.suites ?? []) visit(s);
|
|
39
|
+
};
|
|
40
|
+
for (const s of r.suites ?? []) visit(s);
|
|
41
|
+
} catch { /* missing/!json → no runtime signals */ }
|
|
42
|
+
return out;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Build the repair plan for a unit.
|
|
47
|
+
* @param unitId capability-resolution id (`api/<area>`, `flows/<flow>`, or a screen)
|
|
48
|
+
* @param reportName the bare name used for `.sungen/reports/<name>-audit.json` (+ test-result)
|
|
49
|
+
* @param generatedDir the unit's specs/generated dir (for runtime failures); optional
|
|
50
|
+
*/
|
|
51
|
+
export function planRepair(unitId: string, reportName: string, cwd: string, generatedDir?: string): RepairPlan {
|
|
52
|
+
discoverAndRegisterCapabilities();
|
|
53
|
+
const capId = scoringCapabilityFor(unitId, capabilityRegistry.defaultCapabilityId());
|
|
54
|
+
const rules = (capId ? capabilityRegistry.get(capId)?.repair?.rules : undefined) ?? [];
|
|
55
|
+
|
|
56
|
+
const signals: { source: 'audit' | 'runtime'; text: string }[] = [];
|
|
57
|
+
const auditPath = path.join(cwd, '.sungen', 'reports', `${reportName}-audit.json`);
|
|
58
|
+
if (fs.existsSync(auditPath)) {
|
|
59
|
+
try { for (const f of JSON.parse(fs.readFileSync(auditPath, 'utf8')).findings ?? []) signals.push({ source: 'audit', text: String(f) }); } catch { /* ignore */ }
|
|
60
|
+
}
|
|
61
|
+
if (generatedDir && fs.existsSync(generatedDir)) {
|
|
62
|
+
for (const f of fs.readdirSync(generatedDir)) {
|
|
63
|
+
if (/test-result.*\.json$/.test(f)) for (const msg of failuresFromResult(path.join(generatedDir, f))) signals.push({ source: 'runtime', text: msg });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const proposals: RepairProposal[] = [];
|
|
68
|
+
const unmatched: string[] = [];
|
|
69
|
+
for (const s of signals) {
|
|
70
|
+
const rule = rules.find((r) => r.match.test(s.text));
|
|
71
|
+
if (rule) proposals.push({ source: s.source, signal: s.text, ruleId: rule.id, fix: rule.fix });
|
|
72
|
+
else unmatched.push(s.text);
|
|
73
|
+
}
|
|
74
|
+
return { capability: capId, rulesAvailable: rules.length, proposals, unmatched };
|
|
75
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
export { capabilityRegistry, CapabilityRegistry } from './capabilities/registry';
|
|
9
9
|
export type { CapabilityDescriptor } from './capabilities/registry';
|
|
10
10
|
export type { Sensor, SensorFinding, AdvisoryScanInput, GateInput } from './capabilities/sensor';
|
|
11
|
-
export type { Context, DiscoveryProvider, ContextMapper, GenerationUnit } from './capabilities/context';
|
|
11
|
+
export type { Context, DiscoveryProvider, ContextMapper, GenerationUnit, RepairProvider, RepairRule } from './capabilities/context';
|
|
12
12
|
export { discoverUnitContext } from './orchestrator/context-discovery';
|
|
13
13
|
export type { DiscoveredContext } from './orchestrator/context-discovery';
|
|
14
14
|
|
|
@@ -27,7 +27,7 @@ Parse **name** from `$ARGUMENTS`. If missing, ask the user.
|
|
|
27
27
|
|
|
28
28
|
## API unit mode (driver-api)
|
|
29
29
|
|
|
30
|
-
If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the design loop differs — **no visual capture, no selectors**; the contract is the named-endpoint catalog. **Follow the `sungen-api-design` skill end-to-end** instead of the screen/flow steps below: `sungen context --
|
|
30
|
+
If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the design loop differs — **no visual capture, no selectors**; the contract is the named-endpoint catalog. **Follow the `sungen-api-design` skill end-to-end** instead of the screen/flow steps below: `sungen context --area <name>` (discover) → API viewpoint overview → generate `@api`/`@cases`/flow/`@concurrent`/`@query` scenarios → **`sungen audit --area <name>` gate + the `sungen-reviewer` sub-agent + repair loop to businessDepth ≥ 0.7** → record + trace. Then jump to the "Converge" next-step options (recommend `/sungen:run-test <name>`). The capture / viewpoint-group / selector steps do **not** apply.
|
|
31
31
|
|
|
32
32
|
## Steps
|
|
33
33
|
|
|
@@ -37,15 +37,15 @@ Skip this pre-flight when `--env` matches the base locale (no overlay needed in
|
|
|
37
37
|
If the unit is **api-first**, skip every selector/capture phase (an API test has no DOM). Instead:
|
|
38
38
|
|
|
39
39
|
1. **Resolve the datasource** — ensure the `kind: api` datasource's `base_url` + auth are wired in `qa/datasources.yaml` + `.env.qa` (the `${X_URL}` key from `sungen api init`). A `production` datasource is refused unless `SUNGEN_ALLOW_PROD=1`.
|
|
40
|
-
2. **Compile**: `[ -x ./bin/sungen.js ] && ./bin/sungen.js generate --
|
|
40
|
+
2. **Compile**: `[ -x ./bin/sungen.js ] && ./bin/sungen.js generate --area <name> || npx sungen generate --area <name>` → `specs/generated/api/<name>/`.
|
|
41
41
|
3. **Run**: `npx playwright test specs/generated/api/<name>/<name>.spec.ts` (per-spec JSON results, as below).
|
|
42
42
|
4. **Auto-fix** (no selectors — the failure classes differ): use `sungen-error-mapping`.
|
|
43
43
|
- **401/403** → wire `@hybrid` + `@auth:<role>` (reuse the UI session) or the catalog `Bearer :token` header; suggest `sungen makeauth <role>`.
|
|
44
44
|
- **datasource/base_url unresolved** → set the `${X_URL}` key in `.env.qa`.
|
|
45
45
|
- **missing/empty bound param** → trace `{{var}}` to test-data or a prior `@api` response; fill it.
|
|
46
|
-
- **`expect.status` mismatch** → reconcile against `apis.yaml`/spec (the catalog is the oracle); **never hand-edit the generated spec** (re-`generate --
|
|
46
|
+
- **`expect.status` mismatch** → reconcile against `apis.yaml`/spec (the catalog is the oracle); **never hand-edit the generated spec** (re-`generate --area` instead).
|
|
47
47
|
- **flaky** → enforce self-cleaning flows, per-row isolation (`@cases`), `@concurrent` caps.
|
|
48
|
-
5. **Integrity + trace** — `sungen script-check --
|
|
48
|
+
5. **Integrity + trace** — `sungen script-check --area <name>` (verify the spec is a 1:1 of the Gherkin; on DRIFT re-`generate --area`, never hand-edit) and `sungen trace --area <name>` (process map + HUMAN-LOOP FOCUS). Then report + offer next steps.
|
|
49
49
|
|
|
50
50
|
## Pre-run (phased — per `sungen-selector-fix` skill)
|
|
51
51
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sungen-api-design
|
|
3
|
-
description: The API-first design loop for an api unit (qa/api/<area> or qa/api/flows/<flow>) — discover the catalog, lay out the API viewpoints, generate @api/@cases/flow/@concurrent scenarios, then drive the sungen audit --
|
|
3
|
+
description: The API-first design loop for an api unit (qa/api/<area> or qa/api/flows/<flow>) — discover the catalog, lay out the API viewpoints, generate @api/@cases/flow/@concurrent scenarios, then drive the sungen audit --area gate + reviewer + repair to a high businessDepth (≥0.7). Use when create-test/run-test detects an api unit (no selectors, no visual capture).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# API design loop (driver-api · Orchestration + Harness)
|
|
@@ -10,7 +10,7 @@ Use this when the unit is **api-first** — `qa/api/<area>/` or `qa/api/flows/<f
|
|
|
10
10
|
## The loop (mirror of /sungen:design, API-native)
|
|
11
11
|
|
|
12
12
|
### 1. Discover (no capture)
|
|
13
|
-
Run `sungen context --
|
|
13
|
+
Run `sungen context --area <name>` — it reads the catalog and prints the **endpoints** + the **generation units** (one `matrix` unit per endpoint, an `async` unit per mutating endpoint, a `flow` unit for an api flow). Read `qa/api/<name>/requirements/spec.md` if present. No `apis.yaml` yet? → `sungen api import <openapi|csv>` or `sungen api add --area <name>` first.
|
|
14
14
|
|
|
15
15
|
### 2. API viewpoint overview (by method-profile)
|
|
16
16
|
For each endpoint, cover its viewpoints — severity-weighted by method:
|
|
@@ -29,7 +29,7 @@ Bands: **~70%** success+failure matrix · **~20%** flows (auth/CRUD chains) · *
|
|
|
29
29
|
- **Idempotency**: `@api:<name> @concurrent:N` + `expect {{name.ok_count}} is 1`, cross-checked with `@query` (the DB is the oracle).
|
|
30
30
|
|
|
31
31
|
### 4. Gate + repair (always — businessDepth ≥ 0.7 is the bar)
|
|
32
|
-
Run `sungen audit --
|
|
32
|
+
Run `sungen audit --area <name>`; read `gateStatus` + `findings`. Then the **semantic reviewer** (sungen-reviewer sub-agent, API criteria). Repair **both** (budget 3 rounds), re-audit until PASS:
|
|
33
33
|
|
|
34
34
|
| Finding | Repair |
|
|
35
35
|
|---|---|
|
|
@@ -41,7 +41,7 @@ Run `sungen audit --api <name>`; read `gateStatus` + `findings`. Then the **sema
|
|
|
41
41
|
Stop when the gate PASSes + businessDepth ≥ 0.7, or the budget is exhausted → report residual gaps honestly (mark genuinely-unautomatable cases `@manual` with an oracle). Never fake a pass.
|
|
42
42
|
|
|
43
43
|
### 5. Record + converge
|
|
44
|
-
`sungen manifest --
|
|
44
|
+
`sungen manifest --area <name>` (reuse) and ledger each phase; show the trace + the HUMAN-LOOP FOCUS. (Integrity `script-check`/`trace` for api: see run-test.)
|
|
45
45
|
|
|
46
46
|
## Rules
|
|
47
47
|
- **No HTTP, no selectors** — only `.feature` + the reviewed `apis.yaml` + `test-data`.
|
|
@@ -22,7 +22,7 @@ You are a **Senior QA Engineer**. You structure test cases by viewpoint categori
|
|
|
22
22
|
|
|
23
23
|
## API unit mode (driver-api)
|
|
24
24
|
|
|
25
|
-
If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the design loop differs — **no visual capture, no selectors**; the contract is the named-endpoint catalog. **Follow the `sungen-api-design` skill end-to-end** instead of the screen/flow steps: `sungen context --
|
|
25
|
+
If the unit is **api-first** (`qa/api/<name>/` or `qa/api/flows/<name>/`), the design loop differs — **no visual capture, no selectors**; the contract is the named-endpoint catalog. **Follow the `sungen-api-design` skill end-to-end** instead of the screen/flow steps: `sungen context --area <name>` (discover) → API viewpoint overview → generate `@api`/`@cases`/flow/`@concurrent`/`@query` scenarios → **`sungen audit --area <name>` gate + reviewer + repair loop to businessDepth ≥ 0.7** → record + trace. Then recommend `/sungen-run-test <name>`. The capture / viewpoint-group / selector steps do **not** apply.
|
|
26
26
|
|
|
27
27
|
## Steps
|
|
28
28
|
|
|
@@ -36,10 +36,10 @@ Skip when `--env` matches the base locale.
|
|
|
36
36
|
|
|
37
37
|
If the unit is **api-first**, skip every selector/capture phase (an API test has no DOM):
|
|
38
38
|
1. **Resolve the datasource** — `base_url` + auth wired in `qa/datasources.yaml` + `.env.qa` (`${X_URL}` from `sungen api init`); a `production` datasource is refused unless `SUNGEN_ALLOW_PROD=1`.
|
|
39
|
-
2. **Compile**: `npx sungen generate --
|
|
39
|
+
2. **Compile**: `npx sungen generate --area <name>` → `specs/generated/api/<name>/`.
|
|
40
40
|
3. **Run**: `npx playwright test specs/generated/api/<name>/<name>.spec.ts`.
|
|
41
|
-
4. **Auto-fix** (use `sungen-error-mapping`): 401/403 → `@hybrid`+`@auth` or `Bearer :token` header (`sungen makeauth`); base_url unresolved → set `${X_URL}`; missing param → trace `{{var}}` to test-data/a prior `@api` response; `expect.status` mismatch → reconcile against `apis.yaml` (re-`generate --
|
|
42
|
-
5. **Integrity + trace** — `sungen script-check --
|
|
41
|
+
4. **Auto-fix** (use `sungen-error-mapping`): 401/403 → `@hybrid`+`@auth` or `Bearer :token` header (`sungen makeauth`); base_url unresolved → set `${X_URL}`; missing param → trace `{{var}}` to test-data/a prior `@api` response; `expect.status` mismatch → reconcile against `apis.yaml` (re-`generate --area`, never hand-edit the spec); flaky → self-clean + `@concurrent` caps.
|
|
42
|
+
5. **Integrity + trace** — `sungen script-check --area <name>` (1:1; on DRIFT re-`generate --area`, never hand-edit the spec) + `sungen trace --area <name>` (process map + HUMAN-LOOP FOCUS). Report + offer next steps.
|
|
43
43
|
|
|
44
44
|
## Pre-run (phased — per `sungen-selector-fix` skill)
|
|
45
45
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sungen-api-design
|
|
3
|
-
description: The API-first design loop for an api unit (qa/api/<area> or qa/api/flows/<flow>) — discover the catalog, lay out the API viewpoints, generate @api/@cases/flow/@concurrent scenarios, then drive the sungen audit --
|
|
3
|
+
description: The API-first design loop for an api unit (qa/api/<area> or qa/api/flows/<flow>) — discover the catalog, lay out the API viewpoints, generate @api/@cases/flow/@concurrent scenarios, then drive the sungen audit --area gate + reviewer + repair to a high businessDepth (≥0.7). Use when create-test/run-test detects an api unit (no selectors, no visual capture).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# API design loop (driver-api · Orchestration + Harness)
|
|
@@ -10,7 +10,7 @@ Use this when the unit is **api-first** — `qa/api/<area>/` or `qa/api/flows/<f
|
|
|
10
10
|
## The loop (mirror of /sungen:design, API-native)
|
|
11
11
|
|
|
12
12
|
### 1. Discover (no capture)
|
|
13
|
-
Run `sungen context --
|
|
13
|
+
Run `sungen context --area <name>` — it reads the catalog and prints the **endpoints** + the **generation units** (one `matrix` unit per endpoint, an `async` unit per mutating endpoint, a `flow` unit for an api flow). Read `qa/api/<name>/requirements/spec.md` if present. No `apis.yaml` yet? → `sungen api import <openapi|csv>` or `sungen api add --area <name>` first.
|
|
14
14
|
|
|
15
15
|
### 2. API viewpoint overview (by method-profile)
|
|
16
16
|
For each endpoint, cover its viewpoints — severity-weighted by method:
|
|
@@ -29,7 +29,7 @@ Bands: **~70%** success+failure matrix · **~20%** flows (auth/CRUD chains) · *
|
|
|
29
29
|
- **Idempotency**: `@api:<name> @concurrent:N` + `expect {{name.ok_count}} is 1`, cross-checked with `@query` (the DB is the oracle).
|
|
30
30
|
|
|
31
31
|
### 4. Gate + repair (always — businessDepth ≥ 0.7 is the bar)
|
|
32
|
-
Run `sungen audit --
|
|
32
|
+
Run `sungen audit --area <name>`; read `gateStatus` + `findings`. Then the **semantic reviewer** (sungen-reviewer sub-agent, API criteria). Repair **both** (budget 3 rounds), re-audit until PASS:
|
|
33
33
|
|
|
34
34
|
| Finding | Repair |
|
|
35
35
|
|---|---|
|
|
@@ -41,7 +41,7 @@ Run `sungen audit --api <name>`; read `gateStatus` + `findings`. Then the **sema
|
|
|
41
41
|
Stop when the gate PASSes + businessDepth ≥ 0.7, or the budget is exhausted → report residual gaps honestly (mark genuinely-unautomatable cases `@manual` with an oracle). Never fake a pass.
|
|
42
42
|
|
|
43
43
|
### 5. Record + converge
|
|
44
|
-
`sungen manifest --
|
|
44
|
+
`sungen manifest --area <name>` (reuse) and ledger each phase; show the trace + the HUMAN-LOOP FOCUS. (Integrity `script-check`/`trace` for api: see run-test.)
|
|
45
45
|
|
|
46
46
|
## Rules
|
|
47
47
|
- **No HTTP, no selectors** — only `.feature` + the reviewed `apis.yaml` + `test-data`.
|