@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.
Files changed (68) hide show
  1. package/dist/capabilities/context.d.ts +17 -0
  2. package/dist/capabilities/context.d.ts.map +1 -1
  3. package/dist/capabilities/registry.d.ts +3 -1
  4. package/dist/capabilities/registry.d.ts.map +1 -1
  5. package/dist/capabilities/registry.js.map +1 -1
  6. package/dist/cli/commands/audit.d.ts.map +1 -1
  7. package/dist/cli/commands/audit.js +2 -1
  8. package/dist/cli/commands/audit.js.map +1 -1
  9. package/dist/cli/commands/context.d.ts.map +1 -1
  10. package/dist/cli/commands/context.js +2 -1
  11. package/dist/cli/commands/context.js.map +1 -1
  12. package/dist/cli/commands/delivery.d.ts.map +1 -1
  13. package/dist/cli/commands/delivery.js +13 -1
  14. package/dist/cli/commands/delivery.js.map +1 -1
  15. package/dist/cli/commands/generate.d.ts.map +1 -1
  16. package/dist/cli/commands/generate.js +2 -1
  17. package/dist/cli/commands/generate.js.map +1 -1
  18. package/dist/cli/commands/ledger.d.ts.map +1 -1
  19. package/dist/cli/commands/ledger.js +4 -2
  20. package/dist/cli/commands/ledger.js.map +1 -1
  21. package/dist/cli/commands/manifest.d.ts.map +1 -1
  22. package/dist/cli/commands/manifest.js +2 -1
  23. package/dist/cli/commands/manifest.js.map +1 -1
  24. package/dist/cli/commands/repair.d.ts +8 -0
  25. package/dist/cli/commands/repair.d.ts.map +1 -0
  26. package/dist/cli/commands/repair.js +97 -0
  27. package/dist/cli/commands/repair.js.map +1 -0
  28. package/dist/cli/commands/script-check.d.ts.map +1 -1
  29. package/dist/cli/commands/script-check.js +2 -1
  30. package/dist/cli/commands/script-check.js.map +1 -1
  31. package/dist/cli/commands/trace.d.ts.map +1 -1
  32. package/dist/cli/commands/trace.js +2 -1
  33. package/dist/cli/commands/trace.js.map +1 -1
  34. package/dist/cli/index.js +2 -0
  35. package/dist/cli/index.js.map +1 -1
  36. package/dist/harness/repair.d.ts +20 -0
  37. package/dist/harness/repair.d.ts.map +1 -0
  38. package/dist/harness/repair.js +111 -0
  39. package/dist/harness/repair.js.map +1 -0
  40. package/dist/index.d.ts +1 -1
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +1 -1
  43. package/dist/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +3 -3
  44. package/dist/orchestrator/templates/ai-instructions/claude-skill-api-design.md +4 -4
  45. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +1 -1
  46. package/dist/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +3 -3
  47. package/dist/orchestrator/templates/ai-instructions/github-skill-sungen-api-design.md +4 -4
  48. package/package.json +2 -2
  49. package/src/capabilities/context.ts +19 -0
  50. package/src/capabilities/registry.ts +3 -1
  51. package/src/cli/commands/audit.ts +2 -1
  52. package/src/cli/commands/context.ts +3 -2
  53. package/src/cli/commands/delivery.ts +11 -1
  54. package/src/cli/commands/generate.ts +2 -1
  55. package/src/cli/commands/ledger.ts +4 -2
  56. package/src/cli/commands/manifest.ts +2 -1
  57. package/src/cli/commands/repair.ts +57 -0
  58. package/src/cli/commands/script-check.ts +2 -1
  59. package/src/cli/commands/trace.ts +2 -1
  60. package/src/cli/index.ts +2 -0
  61. package/src/harness/repair.ts +75 -0
  62. package/src/index.ts +1 -1
  63. package/src/orchestrator/templates/ai-instructions/claude-cmd-create-test.md +1 -1
  64. package/src/orchestrator/templates/ai-instructions/claude-cmd-run-test.md +3 -3
  65. package/src/orchestrator/templates/ai-instructions/claude-skill-api-design.md +4 -4
  66. package/src/orchestrator/templates/ai-instructions/copilot-cmd-create-test.md +1 -1
  67. package/src/orchestrator/templates/ai-instructions/copilot-cmd-run-test.md +3 -3
  68. 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 --api <name>` (discover) → API viewpoint overview → generate `@api`/`@cases`/flow/`@concurrent`/`@query` scenarios → **`sungen audit --api <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.
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 --api <name> || npx sungen generate --api <name>` → `specs/generated/api/<name>/`.
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 --api` instead).
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 --api <name>` (verify the spec is a 1:1 of the Gherkin; on DRIFT re-`generate --api`, never hand-edit) and `sungen trace --api <name>` (process map + HUMAN-LOOP FOCUS). Then report + offer next steps.
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 --api gate + reviewer + repair to a high businessDepth (≥0.7). Use when create-test/run-test detects an api unit (no selectors, no visual capture).
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 --api <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.
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 --api <name>`; read `gateStatus` + `findings`. Then the **semantic reviewer** (sungen-reviewer sub-agent, API criteria). Repair **both** (budget 3 rounds), re-audit until PASS:
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 --api <name>` (reuse) and ledger each phase; show the trace + the HUMAN-LOOP FOCUS. (Integrity `script-check`/`trace` for api: see run-test.)
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 --api <name>` (discover) → API viewpoint overview → generate `@api`/`@cases`/flow/`@concurrent`/`@query` scenarios → **`sungen audit --api <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.
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 --api <name>` → `specs/generated/api/<name>/`.
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 --api`, never hand-edit the spec); flaky → self-clean + `@concurrent` caps.
42
- 5. **Integrity + trace** — `sungen script-check --api <name>` (1:1; on DRIFT re-`generate --api`, never hand-edit the spec) + `sungen trace --api <name>` (process map + HUMAN-LOOP FOCUS). Report + offer next steps.
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 --api gate + reviewer + repair to a high businessDepth (≥0.7). Use when create-test/run-test detects an api unit (no selectors, no visual capture).
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 --api <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.
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 --api <name>`; read `gateStatus` + `findings`. Then the **semantic reviewer** (sungen-reviewer sub-agent, API criteria). Repair **both** (budget 3 rounds), re-audit until PASS:
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 --api <name>` (reuse) and ledger each phase; show the trace + the HUMAN-LOOP FOCUS. (Integrity `script-check`/`trace` for api: see run-test.)
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`.