@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.
Files changed (81) hide show
  1. package/dist/cli/commands/audit.d.ts.map +1 -1
  2. package/dist/cli/commands/audit.js +23 -4
  3. package/dist/cli/commands/audit.js.map +1 -1
  4. package/dist/cli/commands/next.js +2 -2
  5. package/dist/cli/commands/next.js.map +1 -1
  6. package/dist/exporters/matrix/build.d.ts.map +1 -1
  7. package/dist/exporters/matrix/build.js +4 -1
  8. package/dist/exporters/matrix/build.js.map +1 -1
  9. package/dist/exporters/matrix/map-loader.d.ts.map +1 -1
  10. package/dist/exporters/matrix/map-loader.js +5 -0
  11. package/dist/exporters/matrix/map-loader.js.map +1 -1
  12. package/dist/exporters/matrix/types.d.ts +11 -0
  13. package/dist/exporters/matrix/types.d.ts.map +1 -1
  14. package/dist/exporters/matrix/types.js.map +1 -1
  15. package/dist/generators/test-generator/utils/selector-resolver.d.ts.map +1 -1
  16. package/dist/generators/test-generator/utils/selector-resolver.js +2 -1
  17. package/dist/generators/test-generator/utils/selector-resolver.js.map +1 -1
  18. package/dist/harness/audit.d.ts +7 -0
  19. package/dist/harness/audit.d.ts.map +1 -1
  20. package/dist/harness/audit.js +77 -9
  21. package/dist/harness/audit.js.map +1 -1
  22. package/dist/harness/flow-contract.d.ts +18 -15
  23. package/dist/harness/flow-contract.d.ts.map +1 -1
  24. package/dist/harness/flow-contract.js +116 -18
  25. package/dist/harness/flow-contract.js.map +1 -1
  26. package/dist/harness/next-step.d.ts +8 -2
  27. package/dist/harness/next-step.d.ts.map +1 -1
  28. package/dist/harness/next-step.js +2 -2
  29. package/dist/harness/next-step.js.map +1 -1
  30. package/dist/harness/quality-gates.d.ts +12 -1
  31. package/dist/harness/quality-gates.d.ts.map +1 -1
  32. package/dist/harness/quality-gates.js +62 -7
  33. package/dist/harness/quality-gates.js.map +1 -1
  34. package/dist/harness/sensors.d.ts.map +1 -1
  35. package/dist/harness/sensors.js +9 -1
  36. package/dist/harness/sensors.js.map +1 -1
  37. package/dist/harness/spec-branches.d.ts +88 -0
  38. package/dist/harness/spec-branches.d.ts.map +1 -0
  39. package/dist/harness/spec-branches.js +280 -0
  40. package/dist/harness/spec-branches.js.map +1 -0
  41. package/dist/harness/spec-coverage.d.ts +1 -1
  42. package/dist/harness/spec-coverage.js +4 -4
  43. package/dist/harness/spec-coverage.js.map +1 -1
  44. package/dist/harness/viewpoint-baseline.d.ts +9 -0
  45. package/dist/harness/viewpoint-baseline.d.ts.map +1 -1
  46. package/dist/harness/viewpoint-baseline.js +33 -3
  47. package/dist/harness/viewpoint-baseline.js.map +1 -1
  48. package/dist/harness/viewpoint-ledger.d.ts.map +1 -1
  49. package/dist/harness/viewpoint-ledger.js +63 -5
  50. package/dist/harness/viewpoint-ledger.js.map +1 -1
  51. package/dist/orchestrator/templates/ai-src/commands/add-flow.md +16 -0
  52. package/dist/orchestrator/templates/ai-src/commands/create-test.md +10 -1
  53. package/dist/orchestrator/templates/ai-src/commands/delivery.md +9 -2
  54. package/dist/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +17 -0
  55. package/dist/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +42 -2
  56. package/dist/utils/ref-key.d.ts +30 -0
  57. package/dist/utils/ref-key.d.ts.map +1 -0
  58. package/dist/utils/ref-key.js +48 -0
  59. package/dist/utils/ref-key.js.map +1 -0
  60. package/package.json +3 -3
  61. package/src/cli/commands/audit.ts +22 -3
  62. package/src/cli/commands/next.ts +2 -2
  63. package/src/exporters/matrix/build.ts +4 -1
  64. package/src/exporters/matrix/map-loader.ts +5 -0
  65. package/src/exporters/matrix/types.ts +11 -0
  66. package/src/generators/test-generator/utils/selector-resolver.ts +2 -1
  67. package/src/harness/audit.ts +81 -11
  68. package/src/harness/flow-contract.ts +128 -17
  69. package/src/harness/next-step.ts +10 -4
  70. package/src/harness/quality-gates.ts +64 -6
  71. package/src/harness/sensors.ts +9 -1
  72. package/src/harness/spec-branches.ts +346 -0
  73. package/src/harness/spec-coverage.ts +4 -4
  74. package/src/harness/viewpoint-baseline.ts +41 -6
  75. package/src/harness/viewpoint-ledger.ts +56 -4
  76. package/src/orchestrator/templates/ai-src/commands/add-flow.md +16 -0
  77. package/src/orchestrator/templates/ai-src/commands/create-test.md +10 -1
  78. package/src/orchestrator/templates/ai-src/commands/delivery.md +9 -2
  79. package/src/orchestrator/templates/ai-src/skills/sungen-harness-audit/SKILL.md +17 -0
  80. package/src/orchestrator/templates/ai-src/skills/sungen-tc-generation/SKILL.md +42 -2
  81. 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 ST_AUTH_001's spec, which this project does not hold."
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
- When User go to [Awards] page
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
+ }