@sun-asterisk/sungen 3.2.25 → 3.2.27
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/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +23 -4
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/next.js +2 -2
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/exporters/matrix/build.d.ts.map +1 -1
- package/dist/exporters/matrix/build.js +4 -1
- package/dist/exporters/matrix/build.js.map +1 -1
- package/dist/exporters/matrix/map-loader.d.ts.map +1 -1
- package/dist/exporters/matrix/map-loader.js +5 -0
- package/dist/exporters/matrix/map-loader.js.map +1 -1
- package/dist/exporters/matrix/types.d.ts +11 -0
- package/dist/exporters/matrix/types.d.ts.map +1 -1
- package/dist/exporters/matrix/types.js.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
- package/dist/generators/test-generator/utils/selector-resolver.js +2 -1
- package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
- package/dist/harness/audit.d.ts +7 -0
- package/dist/harness/audit.d.ts.map +1 -1
- package/dist/harness/audit.js +77 -9
- package/dist/harness/audit.js.map +1 -1
- package/dist/harness/flow-contract.d.ts +18 -15
- package/dist/harness/flow-contract.d.ts.map +1 -1
- package/dist/harness/flow-contract.js +116 -18
- package/dist/harness/flow-contract.js.map +1 -1
- package/dist/harness/next-step.d.ts +8 -2
- package/dist/harness/next-step.d.ts.map +1 -1
- package/dist/harness/next-step.js +2 -2
- package/dist/harness/next-step.js.map +1 -1
- package/dist/harness/quality-gates.d.ts +12 -1
- package/dist/harness/quality-gates.d.ts.map +1 -1
- package/dist/harness/quality-gates.js +62 -7
- package/dist/harness/quality-gates.js.map +1 -1
- package/dist/harness/sensors.d.ts.map +1 -1
- package/dist/harness/sensors.js +9 -1
- package/dist/harness/sensors.js.map +1 -1
- package/dist/harness/spec-branches.d.ts +88 -0
- package/dist/harness/spec-branches.d.ts.map +1 -0
- package/dist/harness/spec-branches.js +280 -0
- package/dist/harness/spec-branches.js.map +1 -0
- package/dist/harness/spec-coverage.d.ts +1 -1
- package/dist/harness/spec-coverage.js +4 -4
- package/dist/harness/spec-coverage.js.map +1 -1
- package/dist/harness/viewpoint-baseline.d.ts +9 -0
- package/dist/harness/viewpoint-baseline.d.ts.map +1 -1
- package/dist/harness/viewpoint-baseline.js +33 -3
- package/dist/harness/viewpoint-baseline.js.map +1 -1
- package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
- package/dist/harness/viewpoint-ledger.js +63 -5
- package/dist/harness/viewpoint-ledger.js.map +1 -1
- package/dist/orchestrator/templates/ai-src/commands/add-flow.md +16 -0
- package/dist/orchestrator/templates/ai-src/commands/create-test.md +10 -1
- package/dist/orchestrator/templates/ai-src/commands/delivery.md +9 -2
- package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +17 -0
- package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +42 -2
- package/dist/utils/ref-key.d.ts +30 -0
- package/dist/utils/ref-key.d.ts.map +1 -0
- package/dist/utils/ref-key.js +48 -0
- package/dist/utils/ref-key.js.map +1 -0
- package/package.json +3 -3
- package/src/cli/commands/audit.ts +22 -3
- package/src/cli/commands/next.ts +2 -2
- package/src/exporters/matrix/build.ts +4 -1
- package/src/exporters/matrix/map-loader.ts +5 -0
- package/src/exporters/matrix/types.ts +11 -0
- package/src/generators/test-generator/utils/selector-resolver.ts +2 -1
- package/src/harness/audit.ts +81 -11
- package/src/harness/flow-contract.ts +128 -17
- package/src/harness/next-step.ts +10 -4
- package/src/harness/quality-gates.ts +64 -6
- package/src/harness/sensors.ts +9 -1
- package/src/harness/spec-branches.ts +346 -0
- package/src/harness/spec-coverage.ts +4 -4
- package/src/harness/viewpoint-baseline.ts +41 -6
- package/src/harness/viewpoint-ledger.ts +56 -4
- package/src/orchestrator/templates/ai-src/commands/add-flow.md +16 -0
- package/src/orchestrator/templates/ai-src/commands/create-test.md +10 -1
- package/src/orchestrator/templates/ai-src/commands/delivery.md +9 -2
- package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +17 -0
- package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +42 -2
- package/src/utils/ref-key.ts +43 -0
|
@@ -68,6 +68,23 @@ Use these when repairing GATE/DEPTH findings for the hard viewpoints (cart/detai
|
|
|
68
68
|
4. **EP/data families are OK.** A `duplicates` cluster with `sameDataLikely=false` is an intentional equivalence-partition family (e.g. many invalid-email cases) — keep it; only collapse `sameDataLikely=true` exact duplicates.
|
|
69
69
|
5. **Advisory findings — surface, don't gate.** `MANUAL-REASON-MISMATCH` → fix the scenario's `@manual:Mx` code (so the planner recommends the right driver) during repair. `CAPABILITY-SUGGESTION` → **present it to the user as a next-step option** (e.g. "N @manual could be automated — `sungen capability add api db`?"), **recommend-only — never auto-install**. `VERIFICATION-OUT-OF-SCOPE (api|db)` → the unit uses `@api`/`@query`/`@requires:api|db` verification the project's recorded **test type** never opted into (E2E/UI-only per `capabilities.yaml`, and the viewpoint doesn't ask for it). During repair: **rewrite the oracle to be UI-observable** (or downgrade the deep check to an `(optional deep check: …)` note); only keep the API/DB verification if the project genuinely tests that layer — then record it (`verification: [ui, api]` / `sungen capability add`). Keep API/DB-in-E2E to the ≤20% band. Neither of these fails the gate.
|
|
70
70
|
|
|
71
|
+
6. **A gate that contradicts the spec's intent is a question, not a repair.** When the only way to
|
|
72
|
+
satisfy a finding is to change what the spec deliberately asked for — widening an entry variant the
|
|
73
|
+
spec keeps light so `FLOW-SCOPE-CREEP` stops firing, renaming a title around a trigger word so a
|
|
74
|
+
claim rule stops firing, adding an assertion the spec never demands — **stop and put the conflict
|
|
75
|
+
to the user** (`AskUserQuestion`: the finding, the spec passage it collides with, the two ways out).
|
|
76
|
+
A score reached by editing toward the gate is not a measurement of the suite; it is a measurement
|
|
77
|
+
of how well the gate was gamed, and the human reviewer will read it as over-testing or a false
|
|
78
|
+
claim. Where the harness provides a declaration route — `flows:` with a per-flow `outcome:`, a
|
|
79
|
+
`status: deferred` with a reason, `@manual` naming the gesture — that route is the fix, never the
|
|
80
|
+
scenario.
|
|
81
|
+
7. **`--accept-viewpoint` is a QA decision. Never run it.** `atomicLedger` and `traceability` are
|
|
82
|
+
evidence only while `test-viewpoint.md` is independent of what was generated. `sungen next` lists
|
|
83
|
+
the acceptance as a `⚖ decide` step: present it (the diff of declared ids, what was added, what was
|
|
84
|
+
dropped) and let the QA run the command. An agent that accepts the yardstick it just wrote makes
|
|
85
|
+
both axes read 100% by construction — and the spec's Exception Flow it forgot stops being missing
|
|
86
|
+
from anything.
|
|
87
|
+
|
|
71
88
|
## Discovery / fallback tree (when input is limited)
|
|
72
89
|
|
|
73
90
|
```
|
|
@@ -340,6 +340,9 @@ Security: [S1 – admin only]
|
|
|
340
340
|
`sungen audit` enforces these. Generate compliant output up front:
|
|
341
341
|
|
|
342
342
|
1. **Taxonomy-match** (`VP-TAXONOMY-MISMATCH`, gate-FAIL) — when `test-viewpoint.md` declares its own viewpoint IDs (e.g. `VP0`, `VP1`, … `VP12`, `MS-HP-001`, `MS-EH-001`), **reuse those IDs verbatim as the scenario codes**. Do NOT invent a generic `VP-UI / VP-LOGIC / VP-VAL` scheme — that breaks the coverage matrix. Only fall back to `VP-<CATEGORY>-<NNN>` when the viewpoint file declares no IDs.
|
|
343
|
+
- **`--accept-viewpoint` is the QA's command, not yours.** `sungen next` shows it as a `⚖ decide`
|
|
344
|
+
step. Present the declared-id diff and stop; a yardstick accepted by the process it measures
|
|
345
|
+
reads 100% by construction.
|
|
343
346
|
- **Match the scenarios to the file — never the file to the scenarios.** A filled `test-viewpoint.md` is an input; do not rewrite its declarations to fit what you generated. That is not compliance, it is moving the yardstick: `traceability` + `atomicLedger` then read 100% by construction and a dropped viewpoint stops being missing from anything. Disagree with the taxonomy → propose the diff and ask. `sungen audit` reports `VIEWPOINT-BASELINE-CHANGED` and excludes both axes until a human accepts the change (`sungen audit --screen <name> --accept-viewpoint`).
|
|
344
347
|
2. **Spec-coverage triggers** (`TRIGGER-UNCOVERED`, gate-FAIL) — the Validation-Rules table lists a **trigger** per constraint (e.g. `blur, submit`). Generate one scenario **per (constraint × trigger)** — a `format` rule validating *on blur AND on submit* needs BOTH a blur scenario (`press Tab`) and a submit scenario (`click [Submit]` / `press Enter`). Never collapse the trigger × input matrix to one representative case.
|
|
345
348
|
3. **Claim-Proof** (`CLAIM-UNPROVEN`) — a title claiming `all`/`only`/`every`/`single`/`correct`/`same`/`changes`/`hidden`/`cleared`/`restored`/`independent`/`sanitized`/`announces` MUST have the matching assertion (`see all …`, count, `remember`+compare, `is hidden`, return-and-assert-empty, etc.). If the title promises it, the steps must prove it.
|
|
@@ -718,7 +721,7 @@ flows:
|
|
|
718
721
|
branchFrom: "BF step 1, the control tapped twice"
|
|
719
722
|
outcome: "One request, one record"
|
|
720
723
|
status: pending-clarification # the spec is silent — ASK, never assume a guard
|
|
721
|
-
reason: "The guard lives in
|
|
724
|
+
reason: "The guard lives in SCREEN_A_001's spec, which this project does not hold."
|
|
722
725
|
```
|
|
723
726
|
|
|
724
727
|
Four statuses, and **silence is not one of them**: `covered` · `deferred` · `pending-clarification`
|
|
@@ -728,6 +731,36 @@ missing flow. `sungen audit` then measures `flowCoverage` per DECLARED FLOW and
|
|
|
728
731
|
`FLOW-UNCOVERED` (declared, nobody wrote it), `FLOW-UNDECLARED` (a scenario claiming a flow id the
|
|
729
732
|
inventory never declares), `FLOW-STATUS-UNREASONED` and `FLOW-INVENTORY-MISSING`.
|
|
730
733
|
|
|
734
|
+
**Enumerate every branch the spec declares — do not rely on reading carefully.** Before writing
|
|
735
|
+
scenarios, list each mutually-exclusive branch the spec makes explicit, one line per arm:
|
|
736
|
+
|
|
737
|
+
- every `### Exception Flow X` / `### Alternative Flow X` heading;
|
|
738
|
+
- every row of a decision table (`DEC-*`, `BR-*`, any table of conditions → outcomes);
|
|
739
|
+
- every arm of an if/elif/else cascade in pseudocode;
|
|
740
|
+
- every state transition a state machine declares.
|
|
741
|
+
|
|
742
|
+
Each arm needs its OWN scenario, or a written exclusion. **Covering a sibling arm proves nothing
|
|
743
|
+
about this one** — and two scenarios that assert the same thing under different names are one test
|
|
744
|
+
counted twice, which is worse than a gap because the coverage sheet reports it as two.
|
|
745
|
+
`sungen audit` reports `SPEC-BRANCH-UNCOVERED` and `BRANCH-OVERCLAIMED`. This rule existed as
|
|
746
|
+
prose before and was missed three times in three flows; it is enumerated now for that reason.
|
|
747
|
+
|
|
748
|
+
**Two viewpoints per UI region, not one.** A region that has both conditional rendering (`DEC-*`)
|
|
749
|
+
and an acceptance scenario describing a click needs a case for EACH: "render — DEC-xxx" and
|
|
750
|
+
"interaction — click → destination". Finishing the render half is the easy half, and stopping there
|
|
751
|
+
is the common failure. Every navigation target the spec names needs a click-through case
|
|
752
|
+
(`NAV-TARGET-ABSENT`), even when this flow does not consume the destination — a context param
|
|
753
|
+
handed to another screen is that screen's input, and the handoff is where it goes wrong.
|
|
754
|
+
|
|
755
|
+
**A deny case needs its allow case.** "permission denied → content hidden" passes just as happily
|
|
756
|
+
when the content is hidden for everyone. Pair it with "permission granted → content shown", the
|
|
757
|
+
way a boundary needs `min-1 / min / max / max+1` (`PERMISSION-PAIR-MISSING`).
|
|
758
|
+
|
|
759
|
+
**State that ARRIVES with the data is a different case from state the test creates.** A
|
|
760
|
+
discriminator field you can only observe at load (an item already favourited before the page
|
|
761
|
+
opens) is a different oracle timing from the same field set by an action inside the test. Both are
|
|
762
|
+
needed; the first is usually `@manual:M1` or a data-factory fixture.
|
|
763
|
+
|
|
731
764
|
**One id per atomic CLAIM in the viewpoint.** The flow id groups; the viewpoint id identifies.
|
|
732
765
|
Writing `FL-BF-001` on four different claims makes the ledger count four items while traceability
|
|
733
766
|
sees one, so the coverage arithmetic and "which test proves this?" are both wrong and neither
|
|
@@ -791,6 +824,13 @@ is a gap to REPORT, not to quietly absorb.
|
|
|
791
824
|
that never touches `outcome.screen` and is not a guard (`EH`) or error-recovery (`ER`) belongs in a
|
|
792
825
|
DIFFERENT flow — propose the split instead of writing it here (`FLOW-SCOPE-CREEP` will flag it).
|
|
793
826
|
Auth persistence across transitions is part of `EH` unless the project declares it its own phase.
|
|
827
|
+
**The exception is declared, not widened:** when the spec KEEPS a variant deliberately light — an
|
|
828
|
+
entry variant that only proves the alternative entry reaches the action bar, without repeating the
|
|
829
|
+
full assertion the basic flow already carries — declare that flow in `flows:` with its own
|
|
830
|
+
`outcome:` and the audit judges it against that outcome. Never widen the scenario to satisfy the
|
|
831
|
+
gate; a reviewer reads the result as over-testing, and the finding was the thing that was wrong.
|
|
832
|
+
When a gate and the spec's stated intent collide and no declaration route exists, stop and put the
|
|
833
|
+
conflict to the user — do not edit toward the score.
|
|
794
834
|
|
|
795
835
|
**Manual in flows**: always `@manual:Mx` with the reason code — bare `@manual` is flagged
|
|
796
836
|
(`MANUAL-CODE-MISSING`) because the capability planner cannot route it. Typical flow deferrals:
|
|
@@ -817,7 +857,7 @@ Feature: Award Submission Flow
|
|
|
817
857
|
|
|
818
858
|
@high
|
|
819
859
|
Scenario: FL-EH-001 Direct access to the award form without login redirects to login
|
|
820
|
-
|
|
860
|
+
Given User is on [Awards] page
|
|
821
861
|
Then User see [Login] page
|
|
822
862
|
```
|
|
823
863
|
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ONE vocabulary for what a `[Reference]` means.
|
|
3
|
+
*
|
|
4
|
+
* The compiler's documented key rule is "the lowercase of the `[Reference]` text, spaces
|
|
5
|
+
* preserved" (`SelectorResolver.generateKey`). The harness re-implemented that rule with its own
|
|
6
|
+
* regex — `/\[([a-z0-9_.-]+):/` — which has no space in it, so a multi-word screen such as
|
|
7
|
+
* `[Basic Info:Email]` compiled, ran and passed, and was NEVER seen by `touchesOutcome`,
|
|
8
|
+
* `reachesOutcome`, phase coverage, handoffs or the navigation-target check. A real project
|
|
9
|
+
* hyphenated every namespace with zero functional change and its audit went 6.9 → 8.9 (#660).
|
|
10
|
+
*
|
|
11
|
+
* Two rules, one place:
|
|
12
|
+
* - `normalizeRefLabel` IS the compiler's key rule. The compiler delegates here.
|
|
13
|
+
* - `screenKey` is the COMPARISON form the harness uses for a screen/namespace: separators are
|
|
14
|
+
* equivalent (`basic info` ≡ `basic-info` ≡ `basic_info`), because a contract author writes
|
|
15
|
+
* `outcome.screen: basic-info` as readily as the feature writes `[Basic Info:…]`, and the
|
|
16
|
+
* harness only ever asks "is this the same screen?" — never "which YAML key resolves?".
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** The compiler's selector-key rule: NFC, lowercase, trimmed, inner whitespace collapsed. */
|
|
20
|
+
export function normalizeRefLabel(label: string): string {
|
|
21
|
+
return label.normalize('NFC').toLowerCase().trim().replace(/\s+/g, ' ');
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** Comparison form for a screen / namespace name — separator-insensitive. */
|
|
25
|
+
export function screenKey(label: string): string {
|
|
26
|
+
return normalizeRefLabel(label).replace(/[\s_-]+/g, ' ').trim();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Every namespace a piece of step text references, in order, as `screenKey`s.
|
|
31
|
+
* `[Screen:Element]` → `screen`; a bare `[Screen]` page reference is included too when `bare`
|
|
32
|
+
* is set (a `see [Done] page` assertion names the screen without an element).
|
|
33
|
+
*/
|
|
34
|
+
export function refNamespaces(text: string, opts: { bare?: boolean } = {}): string[] {
|
|
35
|
+
const out: string[] = [];
|
|
36
|
+
for (const m of text.matchAll(/\[([^\]]+)\]/g)) {
|
|
37
|
+
const inner = m[1];
|
|
38
|
+
const colon = inner.indexOf(':');
|
|
39
|
+
if (colon !== -1) out.push(screenKey(inner.slice(0, colon)));
|
|
40
|
+
else if (opts.bare) out.push(screenKey(inner));
|
|
41
|
+
}
|
|
42
|
+
return out;
|
|
43
|
+
}
|