@qulib/core 0.8.2 → 0.9.0

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 (88) hide show
  1. package/README.md +30 -5
  2. package/bin/qulib.js +2 -3
  3. package/dist/__tests__/playwright-available.d.ts +32 -0
  4. package/dist/__tests__/playwright-available.d.ts.map +1 -0
  5. package/dist/__tests__/playwright-available.js +35 -0
  6. package/dist/adapters/ci-results-adapter.d.ts +67 -0
  7. package/dist/adapters/ci-results-adapter.d.ts.map +1 -0
  8. package/dist/adapters/ci-results-adapter.js +143 -0
  9. package/dist/adapters/cypress-e2e-adapter.d.ts.map +1 -1
  10. package/dist/adapters/cypress-e2e-adapter.js +25 -2
  11. package/dist/adapters/playwright-adapter.d.ts.map +1 -1
  12. package/dist/adapters/playwright-adapter.js +25 -2
  13. package/dist/adapters/pr-metadata-adapter.d.ts +75 -0
  14. package/dist/adapters/pr-metadata-adapter.d.ts.map +1 -0
  15. package/dist/adapters/pr-metadata-adapter.js +146 -0
  16. package/dist/adapters/validate-specs.d.ts +55 -0
  17. package/dist/adapters/validate-specs.d.ts.map +1 -0
  18. package/dist/adapters/validate-specs.js +67 -0
  19. package/dist/baseline/baseline.d.ts +54 -0
  20. package/dist/baseline/baseline.d.ts.map +1 -0
  21. package/dist/baseline/baseline.js +252 -0
  22. package/dist/baseline/baseline.schema.d.ts +233 -0
  23. package/dist/baseline/baseline.schema.d.ts.map +1 -0
  24. package/dist/baseline/baseline.schema.js +59 -0
  25. package/dist/cli/confidence-run.d.ts +16 -0
  26. package/dist/cli/confidence-run.d.ts.map +1 -0
  27. package/dist/cli/confidence-run.js +158 -0
  28. package/dist/cli/index.d.ts +11 -1
  29. package/dist/cli/index.d.ts.map +1 -1
  30. package/dist/cli/index.js +80 -4
  31. package/dist/cli/scaffold-run.d.ts +86 -0
  32. package/dist/cli/scaffold-run.d.ts.map +1 -0
  33. package/dist/cli/scaffold-run.js +232 -0
  34. package/dist/cli/score-automation-run.d.ts +25 -0
  35. package/dist/cli/score-automation-run.d.ts.map +1 -0
  36. package/dist/cli/score-automation-run.js +123 -0
  37. package/dist/examples/notquality-dogfood/fixture.d.ts +166 -0
  38. package/dist/examples/notquality-dogfood/fixture.d.ts.map +1 -0
  39. package/dist/examples/notquality-dogfood/fixture.js +174 -0
  40. package/dist/examples/notquality-dogfood/run.d.ts +34 -0
  41. package/dist/examples/notquality-dogfood/run.d.ts.map +1 -0
  42. package/dist/examples/notquality-dogfood/run.js +139 -0
  43. package/dist/index.d.ts +14 -1
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +11 -0
  46. package/dist/recipes/a11y.d.ts +36 -0
  47. package/dist/recipes/a11y.d.ts.map +1 -0
  48. package/dist/recipes/a11y.js +118 -0
  49. package/dist/recipes/auth.d.ts +38 -0
  50. package/dist/recipes/auth.d.ts.map +1 -0
  51. package/dist/recipes/auth.js +156 -0
  52. package/dist/recipes/index.d.ts +26 -0
  53. package/dist/recipes/index.d.ts.map +1 -0
  54. package/dist/recipes/index.js +41 -0
  55. package/dist/recipes/nav.d.ts +34 -0
  56. package/dist/recipes/nav.d.ts.map +1 -0
  57. package/dist/recipes/nav.js +128 -0
  58. package/dist/recipes/seed.d.ts +34 -0
  59. package/dist/recipes/seed.d.ts.map +1 -0
  60. package/dist/recipes/seed.js +87 -0
  61. package/dist/scaffold-tests.d.ts +21 -0
  62. package/dist/scaffold-tests.d.ts.map +1 -1
  63. package/dist/scaffold-tests.js +12 -2
  64. package/dist/schemas/confidence.schema.d.ts +526 -0
  65. package/dist/schemas/confidence.schema.d.ts.map +1 -0
  66. package/dist/schemas/confidence.schema.js +161 -0
  67. package/dist/schemas/index.d.ts +3 -0
  68. package/dist/schemas/index.d.ts.map +1 -1
  69. package/dist/schemas/index.js +3 -0
  70. package/dist/schemas/recipe.schema.d.ts +66 -0
  71. package/dist/schemas/recipe.schema.d.ts.map +1 -0
  72. package/dist/schemas/recipe.schema.js +45 -0
  73. package/dist/schemas/views.schema.d.ts +234 -0
  74. package/dist/schemas/views.schema.d.ts.map +1 -0
  75. package/dist/schemas/views.schema.js +82 -0
  76. package/dist/tools/scoring/confidence-from-qulib.d.ts +34 -0
  77. package/dist/tools/scoring/confidence-from-qulib.d.ts.map +1 -0
  78. package/dist/tools/scoring/confidence-from-qulib.js +206 -0
  79. package/dist/tools/scoring/confidence-views.d.ts +40 -0
  80. package/dist/tools/scoring/confidence-views.d.ts.map +1 -0
  81. package/dist/tools/scoring/confidence-views.js +163 -0
  82. package/dist/tools/scoring/confidence.d.ts +32 -0
  83. package/dist/tools/scoring/confidence.d.ts.map +1 -0
  84. package/dist/tools/scoring/confidence.js +180 -0
  85. package/dist/tools/scoring/levels.d.ts +15 -0
  86. package/dist/tools/scoring/levels.d.ts.map +1 -0
  87. package/dist/tools/scoring/levels.js +21 -0
  88. package/package.json +13 -7
@@ -0,0 +1,174 @@
1
+ /**
2
+ * notquality DOGFOOD — real delivery signals fixture.
3
+ *
4
+ * P5 — qulib ingests notquality's own delivery signals → Release Confidence.
5
+ *
6
+ * PROVENANCE (all signals gathered 2026-06-04 via `gh` CLI against TapeshN/notquality):
7
+ *
8
+ * E2E run: gh run view 26931370208 -R TapeshN/notquality
9
+ * branch: notquality-app/prod-migrate
10
+ * sha: 5732ed5a37ba46c503d1319da83c5c6f4c8e5cb6
11
+ * workflow: E2E (playwright job, job ID 79451559555)
12
+ * completed: 2026-06-04T04:46:20Z (duration: ~6m4s)
13
+ * conclusion: success
14
+ * test files: 29 spec files on origin/main (git ls-tree -r origin/main)
15
+ * test cases: 194 total test() calls across 29 spec files
16
+ * fixme/skip: 26 test.fixme / test.skip markers
17
+ * active (non-fixme): 194 - 26 = 168 runnable tests
18
+ * all passed (CI conclusion: success)
19
+ *
20
+ * CI run: gh run view 26931370215 -R TapeshN/notquality
21
+ * branch: notquality-app/prod-migrate
22
+ * sha: 5732ed5a37ba46c503d1319da83c5c6f4c8e5cb6
23
+ * workflow: CI (validate job, job ID 79451559554)
24
+ * completed: 2026-06-04T04:46:20Z (duration: ~1m13s)
25
+ * conclusion: success
26
+ * steps: typecheck, lint, validate:bugs, prisma generate, build — all green
27
+ *
28
+ * PR: gh pr view 52 -R TapeshN/notquality --json number,url,reviewDecision,mergeable,statusCheckRollup
29
+ * title: "Run prisma migrate deploy before build on Vercel"
30
+ * branch: notquality-app/prod-migrate
31
+ * number: 52
32
+ * url: https://github.com/TapeshN/notquality/pull/52
33
+ * reviewDecision: "" (no review assigned — open PR, no blocking change requests)
34
+ * mergeable: MERGEABLE
35
+ * status checks: CI validate → SUCCESS, E2E playwright → SUCCESS, Vercel → SUCCESS
36
+ *
37
+ * Repo inventory (gh ls-tree -r origin/main, 2026-06-04):
38
+ * 29 spec files, 77 source .ts/.tsx files (excl. e2e), 19 route pages
39
+ * playwright.config.ts present (.github/workflows/e2e.yml present)
40
+ * CI: .github/workflows/ci.yml present (typecheck + lint + validate:bugs + build)
41
+ * auth: dual auth (iron-session playground + NextAuth platform)
42
+ * test-id hygiene: data-testid used in app/ + e2e/ (29 spec files use getByTestId)
43
+ * challenges: 1 seeded (legacy-bug-hunt-1); 16-card static list page (P5 truth-fix target)
44
+ *
45
+ * COLLECTION TIMESTAMP: 2026-06-04T09:00:00.000Z
46
+ *
47
+ * This fixture is intentionally FROZEN at this point in time. When real delivery
48
+ * signals are updated, create a NEW fixture version (fixture-v2.ts, etc.) and
49
+ * update the integration tests to use the latest. Never silently mutate this file —
50
+ * the provenance citation is load-bearing for the eval/audit trail.
51
+ */
52
+ export const FIXTURE_COLLECTION_TS = '2026-06-04T09:00:00.000Z';
53
+ /**
54
+ * Real CI run data from notquality E2E workflow (run #26931370208).
55
+ * Source: gh run view 26931370208 -R TapeshN/notquality
56
+ */
57
+ export const NOTQUALITY_E2E_RUN = {
58
+ /** ISO-8601 timestamp of run completion. */
59
+ completedAt: '2026-06-04T04:46:20.000Z',
60
+ /** CI build step succeeded (typecheck, lint, validate:bugs, prisma generate, build). */
61
+ buildPassed: true,
62
+ /**
63
+ * 168 runnable tests (194 total test() calls − 26 test.fixme/test.skip markers).
64
+ * All 168 passed in this run. Source: spec-file grep + run conclusion=success.
65
+ */
66
+ testsPassed: 168,
67
+ testsFailed: 0,
68
+ testsErrored: 0,
69
+ /**
70
+ * 26 tests marked test.fixme or test.skip across 16 spec files.
71
+ * These are known quarantined defects (color-contrast a11y, label regression,
72
+ * EVT-001, duplicate challenge-title) — intentional, not infra failures.
73
+ */
74
+ testsFlaky: 0,
75
+ runUrl: 'https://github.com/TapeshN/notquality/actions/runs/26931370208',
76
+ workflowName: 'E2E (playwright)',
77
+ };
78
+ /**
79
+ * Real CI validate-job data from notquality CI workflow (run #26931370215).
80
+ * Source: gh run view 26931370215 -R TapeshN/notquality
81
+ */
82
+ export const NOTQUALITY_CI_RUN = {
83
+ completedAt: '2026-06-04T04:46:20.000Z',
84
+ buildPassed: true,
85
+ testsPassed: 0, // CI job runs lint/typecheck/validate:bugs — no Jest/Vitest unit tests yet
86
+ testsFailed: 0,
87
+ testsErrored: 0,
88
+ runUrl: 'https://github.com/TapeshN/notquality/actions/runs/26931370215',
89
+ workflowName: 'CI (validate)',
90
+ };
91
+ /**
92
+ * Real PR #52 metadata from notquality.
93
+ * Source: gh pr view 52 -R TapeshN/notquality --json number,url,reviewDecision,mergeable,statusCheckRollup
94
+ */
95
+ export const NOTQUALITY_PR_52 = {
96
+ number: 52,
97
+ url: 'https://github.com/TapeshN/notquality/pull/52',
98
+ reviewDecision: null, // no review assigned — open PR, no blocking changes_requested
99
+ mergeable: 'MERGEABLE',
100
+ statusCheckRollup: [
101
+ {
102
+ state: 'SUCCESS',
103
+ name: 'validate',
104
+ targetUrl: 'https://github.com/TapeshN/notquality/actions/runs/26931370215/job/79451559554',
105
+ },
106
+ {
107
+ state: 'SUCCESS',
108
+ name: 'playwright',
109
+ targetUrl: 'https://github.com/TapeshN/notquality/actions/runs/26931370208/job/79451559555',
110
+ },
111
+ {
112
+ state: 'SUCCESS',
113
+ name: 'Vercel',
114
+ targetUrl: 'https://vercel.com/tapeshnagarwal-7364s-projects/notquality-app/5mSLRhKKEdwvnqMoTY4XWxSePFYB',
115
+ },
116
+ {
117
+ state: 'SUCCESS',
118
+ name: 'Vercel Preview Comments',
119
+ targetUrl: 'https://vercel.com/github',
120
+ },
121
+ ],
122
+ noPr: false,
123
+ };
124
+ /**
125
+ * Repo-level automation maturity facts (from static scan of origin/main, 2026-06-04).
126
+ * These facts drive the test-automation EvidenceItem used when qulib_score_automation
127
+ * is held (no live local scan in this fixture — see HELD note below).
128
+ *
129
+ * HELD: The live qulib_score_automation(repoPath) call requires the notquality
130
+ * repo to be available at an absolute path on the build machine and needs the full
131
+ * qulib CLI. The integration test uses these pre-scored facts instead of a live scan.
132
+ * The live scan is operator-gated (run `qulib score-automation <path>` locally).
133
+ */
134
+ export const NOTQUALITY_AUTOMATION_MATURITY = {
135
+ /**
136
+ * Estimated overall automation maturity score (0–100).
137
+ * Basis: Playwright present (framework-adoption ✓), 29 spec files covering 19 routes
138
+ * (test-coverage-breadth ~72%), e2e.yml + ci.yml present (ci-integration ✓),
139
+ * auth-test-coverage present (iron-session + NextAuth both tested ✓),
140
+ * data-testid used in spec files (test-id-hygiene present but not perfect — duplicate
141
+ * challenge-title test-id is a known defect, P5 truth-fix target), no component/unit
142
+ * tests yet (component-test-ratio = 0). Estimated L3 (60–79 range).
143
+ * Conservative estimate: 65/100.
144
+ */
145
+ overallScore: 65,
146
+ level: 3,
147
+ label: 'L3 — building maturity',
148
+ /**
149
+ * Key facts cited (no live scan was run; these are statically-derived):
150
+ * - framework: Playwright (playwright.config.ts present on origin/main)
151
+ * - specFiles: 29 (git ls-tree origin/main | grep "e2e/" | grep "spec.ts")
152
+ * - routePages: 19 (git ls-tree origin/main | grep "app/" | grep "page.tsx")
153
+ * - ciWorkflows: 2 (.github/workflows/ci.yml + e2e.yml)
154
+ * - authTests: yes (e2e/specs/auth/ — 3 spec files, 18 test() calls)
155
+ * - testIdHygiene: partial (data-testid used; duplicate challenge-title known defect)
156
+ * - componentTests: 0 (no vitest/jest unit tests in repo)
157
+ */
158
+ topRecommendations: [
159
+ 'Add vitest/jest unit tests for lib/ (scoring, API helpers) to raise component-test-ratio.',
160
+ 'Fix duplicate data-testid="challenge-title" (breadcrumb vs h1) for unambiguous E2E selectors.',
161
+ 'Add dedicated challenges list + attempt E2E specs once fake list page is replaced with DB truth.',
162
+ ],
163
+ computedAt: FIXTURE_COLLECTION_TS,
164
+ repoPath: 'TapeshN/notquality@5732ed5a (origin/main, 2026-06-04)',
165
+ };
166
+ /**
167
+ * Repository context for the ConfidenceSubject.
168
+ * ref: the commit SHA + branch context; tenantId: 'notquality' (multi-tenant from day one).
169
+ */
170
+ export const NOTQUALITY_SUBJECT = {
171
+ kind: 'release',
172
+ ref: 'TapeshN/notquality@5732ed5a (notquality-app/prod-migrate)',
173
+ tenantId: 'notquality',
174
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * notquality DOGFOOD — runnable example.
3
+ *
4
+ * P5: qulib scoring a real app we own. This is the confidence-layer thesis
5
+ * proven on a live delivery pipeline: qulib ingests notquality's CI results,
6
+ * PR metadata, and automation maturity, then emits a real Release Confidence
7
+ * score + verdict.
8
+ *
9
+ * Run with:
10
+ * npx tsx packages/core/src/examples/notquality-dogfood/run.ts
11
+ *
12
+ * What it does:
13
+ * 1. Loads DATED real-sample fixture (provenance: gh CLI, 2026-06-04).
14
+ * 2. Maps CI run → ciResultsToEvidence (EvidenceItem, source='ci-results').
15
+ * 3. Maps PR metadata → prMetadataToEvidence (EvidenceItem, source='deploy-metadata').
16
+ * 4. Builds a test-automation EvidenceItem from the pre-scored maturity facts.
17
+ * 5. Calls computeReleaseConfidence → fused score + verdict.
18
+ * 6. Prints a structured JSON report to stdout.
19
+ *
20
+ * HELD signals (operator-gated, not run here):
21
+ * - qulib_score_automation live scan (requires local notquality checkout + qulib CLI).
22
+ * Instead this example uses the statically-derived NOTQUALITY_AUTOMATION_MATURITY
23
+ * from the fixture (documented, conservative, clearly labelled as pre-scored).
24
+ * - analyze_app deployed crawl (external HTTP + optional LLM cost).
25
+ * The live-app-quality and accessibility EvidenceItems are omitted here; the
26
+ * pipeline runs correctly with a subset of evidence (partial-evidence honesty).
27
+ *
28
+ * Output format: NDJSON line appended to stdout (one JSON object per run).
29
+ * The rubricVersion field versions the roll-up formula so it can evolve without
30
+ * silently changing meaning (P5 stopgap formula; retires when qulib's own aggregator
31
+ * ships in P3/P4 roadmap).
32
+ */
33
+ export {};
34
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/examples/notquality-dogfood/run.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * notquality DOGFOOD — runnable example.
3
+ *
4
+ * P5: qulib scoring a real app we own. This is the confidence-layer thesis
5
+ * proven on a live delivery pipeline: qulib ingests notquality's CI results,
6
+ * PR metadata, and automation maturity, then emits a real Release Confidence
7
+ * score + verdict.
8
+ *
9
+ * Run with:
10
+ * npx tsx packages/core/src/examples/notquality-dogfood/run.ts
11
+ *
12
+ * What it does:
13
+ * 1. Loads DATED real-sample fixture (provenance: gh CLI, 2026-06-04).
14
+ * 2. Maps CI run → ciResultsToEvidence (EvidenceItem, source='ci-results').
15
+ * 3. Maps PR metadata → prMetadataToEvidence (EvidenceItem, source='deploy-metadata').
16
+ * 4. Builds a test-automation EvidenceItem from the pre-scored maturity facts.
17
+ * 5. Calls computeReleaseConfidence → fused score + verdict.
18
+ * 6. Prints a structured JSON report to stdout.
19
+ *
20
+ * HELD signals (operator-gated, not run here):
21
+ * - qulib_score_automation live scan (requires local notquality checkout + qulib CLI).
22
+ * Instead this example uses the statically-derived NOTQUALITY_AUTOMATION_MATURITY
23
+ * from the fixture (documented, conservative, clearly labelled as pre-scored).
24
+ * - analyze_app deployed crawl (external HTTP + optional LLM cost).
25
+ * The live-app-quality and accessibility EvidenceItems are omitted here; the
26
+ * pipeline runs correctly with a subset of evidence (partial-evidence honesty).
27
+ *
28
+ * Output format: NDJSON line appended to stdout (one JSON object per run).
29
+ * The rubricVersion field versions the roll-up formula so it can evolve without
30
+ * silently changing meaning (P5 stopgap formula; retires when qulib's own aggregator
31
+ * ships in P3/P4 roadmap).
32
+ */
33
+ import { ciResultsToEvidence } from '../../adapters/ci-results-adapter.js';
34
+ import { prMetadataToEvidence } from '../../adapters/pr-metadata-adapter.js';
35
+ import { computeReleaseConfidence } from '../../tools/scoring/confidence.js';
36
+ import { FIXTURE_COLLECTION_TS, NOTQUALITY_E2E_RUN, NOTQUALITY_PR_52, NOTQUALITY_AUTOMATION_MATURITY, NOTQUALITY_SUBJECT, } from './fixture.js';
37
+ // ---------------------------------------------------------------------------
38
+ // Build the evidence bundle from real notquality delivery signals
39
+ // ---------------------------------------------------------------------------
40
+ /**
41
+ * E2E CI run → ci-results evidence item.
42
+ * Source: run #26931370208, E2E workflow, 2026-06-04.
43
+ */
44
+ const e2eEvidence = ciResultsToEvidence(NOTQUALITY_E2E_RUN, FIXTURE_COLLECTION_TS);
45
+ /**
46
+ * PR #52 metadata → deploy-metadata evidence item.
47
+ * Source: gh pr view 52 -R TapeshN/notquality, 2026-06-04.
48
+ */
49
+ const prEvidence = prMetadataToEvidence({
50
+ ...NOTQUALITY_PR_52,
51
+ statusCheckRollup: NOTQUALITY_PR_52.statusCheckRollup.map((c) => ({ ...c })),
52
+ }, FIXTURE_COLLECTION_TS);
53
+ /**
54
+ * Automation maturity → test-automation evidence item.
55
+ * Source: static scan of origin/main, 2026-06-04.
56
+ * NOTE: This is a pre-scored estimate. Live qulib_score_automation(repoPath)
57
+ * is the authoritative signal; this is the operator-held substitute.
58
+ */
59
+ const automationEvidence = {
60
+ source: 'test-automation',
61
+ score: NOTQUALITY_AUTOMATION_MATURITY.overallScore,
62
+ weight: 0.22,
63
+ applicability: 'applicable',
64
+ blocking: false,
65
+ evidence: [
66
+ `Automation maturity: ${NOTQUALITY_AUTOMATION_MATURITY.label} (score ${NOTQUALITY_AUTOMATION_MATURITY.overallScore})`,
67
+ `Source: static scan of ${NOTQUALITY_AUTOMATION_MATURITY.repoPath}`,
68
+ '29 E2E spec files, 168 runnable tests (26 fixme/skip quarantined), Playwright + CI wired.',
69
+ 'No vitest/jest unit tests yet (component-test-ratio = 0).',
70
+ ],
71
+ recommendations: NOTQUALITY_AUTOMATION_MATURITY.topRecommendations.slice(),
72
+ reason: undefined,
73
+ collectedAt: FIXTURE_COLLECTION_TS,
74
+ collector: {
75
+ tool: 'qulib_score_automation.pre-scored',
76
+ inputRef: NOTQUALITY_AUTOMATION_MATURITY.repoPath,
77
+ },
78
+ };
79
+ // ---------------------------------------------------------------------------
80
+ // Assemble ConfidenceInput and compute the score
81
+ // ---------------------------------------------------------------------------
82
+ const input = {
83
+ subject: NOTQUALITY_SUBJECT,
84
+ evidence: [e2eEvidence, prEvidence, automationEvidence],
85
+ policy: {
86
+ passThreshold: 80,
87
+ failThreshold: 30,
88
+ maxListLength: 5,
89
+ requiredSources: [],
90
+ // Default weights apply; explicit ci-results weight already on the EvidenceItem.
91
+ },
92
+ };
93
+ const result = computeReleaseConfidence(input);
94
+ // ---------------------------------------------------------------------------
95
+ // Emit the structured report
96
+ // ---------------------------------------------------------------------------
97
+ const report = {
98
+ rubricVersion: 'p5-dogfood-v1',
99
+ collectionTimestamp: FIXTURE_COLLECTION_TS,
100
+ tenantId: NOTQUALITY_SUBJECT.tenantId,
101
+ subject: NOTQUALITY_SUBJECT.ref,
102
+ sources: {
103
+ e2eRun: NOTQUALITY_E2E_RUN.runUrl,
104
+ ciRun: 'https://github.com/TapeshN/notquality/actions/runs/26931370215',
105
+ pr: NOTQUALITY_PR_52.url,
106
+ automationMaturity: `pre-scored from ${NOTQUALITY_AUTOMATION_MATURITY.repoPath}`,
107
+ },
108
+ heldSignals: [
109
+ 'qulib_score_automation live scan (operator-gated: requires local notquality checkout)',
110
+ 'analyze_app deployed crawl (operator-gated: external HTTP + optional LLM cost)',
111
+ ],
112
+ confidence: {
113
+ score: result.confidenceScore,
114
+ verdict: result.verdict,
115
+ level: result.level,
116
+ label: result.label,
117
+ },
118
+ contributions: result.contributions.map((c) => ({
119
+ source: c.source,
120
+ score: c.score,
121
+ effectiveWeight: c.effectiveWeight,
122
+ applicability: c.applicability,
123
+ })),
124
+ topRisks: result.topRisks,
125
+ recommendations: result.recommendedNextChecks,
126
+ honestyNotes: result.honestyNotes,
127
+ scoreFormula: result.scoreFormula,
128
+ };
129
+ // eslint-disable-next-line no-console
130
+ console.log(JSON.stringify(report, null, 2));
131
+ // Print a human-readable summary line on stderr for quick reading in CI.
132
+ const verdictEmoji = {
133
+ ship: 'SHIP',
134
+ caution: 'CAUTION',
135
+ hold: 'HOLD',
136
+ block: 'BLOCK',
137
+ };
138
+ const v = verdictEmoji[result.verdict] ?? result.verdict.toUpperCase();
139
+ process.stderr.write(`[notquality dogfood] confidence=${result.confidenceScore ?? 'null'} verdict=${v} (${result.label})\n`);
package/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export { analyzeApp } from './analyze.js';
2
+ export { slugifyUrl, defaultBaselineRoot, saveBaseline, loadBaseline, listBaselines, deleteBaseline, compareBaselines, } from './baseline/baseline.js';
3
+ export type { BaselineGap, BaselineSnapshot, BaselineDeltaItem, BaselineDelta, } from './baseline/baseline.schema.js';
2
4
  export { toAgentSummary } from './agent-summary.js';
3
5
  export type { AgentSummary, AgentSummaryPolicy, AgentGate, CoverageStatus, AgentSummaryCostSummary, } from './agent-summary.js';
4
6
  export { detectAuth, validateStorageState, evaluateStorageStateValidity, preflightStorageStateFile, waitForReturnToOrigin, } from './tools/auth/detect.js';
@@ -13,6 +15,7 @@ export { computeApiCoverage } from './tools/scoring/api-coverage.js';
13
15
  export type { ApiCoverageResult, ApiEndpointCoverage } from './tools/scoring/api-coverage.js';
14
16
  export { scaffoldTests } from './scaffold-tests.js';
15
17
  export type { ScaffoldOptions, ScaffoldResult, ProjectConfig } from './scaffold-tests.js';
18
+ export { expandRecipes, buildAuthScenarios, buildA11yScenarios, buildNavScenarios, buildSeedScenarios } from './recipes/index.js';
16
19
  export { createProvider } from './llm/provider-registry.js';
17
20
  export { resolveMaxOutputTokensPerLlmCall } from './schemas/config.schema.js';
18
21
  export { resolveScanStateBaseDir, resolveReportDir } from './harness/state-manager.js';
@@ -23,5 +26,15 @@ export { NoopTelemetrySink } from './telemetry/telemetry.interface.js';
23
26
  export { redactUrlForTelemetry } from './telemetry/emit.js';
24
27
  export type { LlmCallResult, LlmProvider } from './llm/provider.interface.js';
25
28
  export type { CallLlmConfigSlice } from './llm/provider.js';
26
- export type { HarnessConfig, AuthConfig, RouteInventory, GapAnalysis, RepoAnalysis, DetectedAuth, AuthExploration, AuthPath, AuthPathRequirements, CostIntelligence, LlmUsageRecord, RepeatedAiPattern, DeterministicMaturity, PublicSurface, AutomationMaturity, AutomationMaturityDimension, FrameworkDetectionResult, DetectedFrameworkPrimary, } from './schemas/index.js';
29
+ export type { HarnessConfig, AuthConfig, RouteInventory, GapAnalysis, RepoAnalysis, DetectedAuth, AuthExploration, AuthPath, AuthPathRequirements, CostIntelligence, LlmUsageRecord, RepeatedAiPattern, DeterministicMaturity, PublicSurface, AutomationMaturity, AutomationMaturityDimension, FrameworkDetectionResult, DetectedFrameworkPrimary, RecipeId, RecipeConfig, } from './schemas/index.js';
30
+ export { RecipeIdSchema } from './schemas/index.js';
31
+ export { computeReleaseConfidence } from './tools/scoring/confidence.js';
32
+ export { ciResultsToEvidence } from './adapters/ci-results-adapter.js';
33
+ export type { CiRunInput } from './adapters/ci-results-adapter.js';
34
+ export { prMetadataToEvidence } from './adapters/pr-metadata-adapter.js';
35
+ export type { PrMetadataInput, StatusCheck, ReviewDecision, MergeableState } from './adapters/pr-metadata-adapter.js';
36
+ export { buildConfidenceInputFromQulib } from './tools/scoring/confidence-from-qulib.js';
37
+ export { diffConfidence, deriveInbox, buildReplay, toAuditEntry } from './tools/scoring/confidence-views.js';
38
+ export type { EvidenceSourceKind, EvidenceItem, ConfidenceSubject, ConfidenceInput, ConfidencePolicy, ConfidenceVerdict, ConfidenceContribution, ReleaseConfidence, DeliveryTrafficPoint, InboxItem, InboxItemKind, ReplayStep, ReplayTrace, AuditEntry, } from './schemas/index.js';
39
+ export { EvidenceSourceKindSchema, EvidenceItemSchema, ConfidenceSubjectSchema, ConfidenceInputSchema, ConfidencePolicySchema, ConfidenceVerdictSchema, ReleaseConfidenceSchema, } from './schemas/index.js';
27
40
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,YAAY,EACV,YAAY,EACZ,kBAAkB,EAClB,SAAS,EACT,cAAc,EACd,uBAAuB,GACxB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,UAAU,EACV,oBAAoB,EACpB,4BAA4B,EAC5B,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,yBAAyB,EACzB,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,kCAAkC,CAAC;AAC1G,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,6BAA6B,CAAC;AAC7F,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AAC7G,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,YAAY,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAC;AAC9F,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EAAE,gCAAgC,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AACvF,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACjF,YAAY,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AACrE,YAAY,EACV,aAAa,EACb,cAAc,EACd,kBAAkB,GACnB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oCAAoC,CAAC;AACvE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAC9E,YAAY,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAC5D,YAAY,EACV,aAAa,EACb,UAAU,EACV,cAAc,EACd,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,oBAAoB,EACpB,gBAAgB,EAChB,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,aAAa,EACb,kBAAkB,EAClB,2BAA2B,EAC3B,wBAAwB,EACxB,wBAAwB,GACzB,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { analyzeApp } from './analyze.js';
2
+ export { slugifyUrl, defaultBaselineRoot, saveBaseline, loadBaseline, listBaselines, deleteBaseline, compareBaselines, } from './baseline/baseline.js';
2
3
  export { toAgentSummary } from './agent-summary.js';
3
4
  export { detectAuth, validateStorageState, evaluateStorageStateValidity, preflightStorageStateFile, waitForReturnToOrigin, } from './tools/auth/detect.js';
4
5
  export { exploreAuth } from './tools/auth/explore.js';
@@ -8,8 +9,18 @@ export { discoverApiSurface, discoverApiSurfaceWithRepo } from './tools/repo/api
8
9
  export { computeAutomationMaturity } from './tools/scoring/automation-maturity.js';
9
10
  export { computeApiCoverage } from './tools/scoring/api-coverage.js';
10
11
  export { scaffoldTests } from './scaffold-tests.js';
12
+ export { expandRecipes, buildAuthScenarios, buildA11yScenarios, buildNavScenarios, buildSeedScenarios } from './recipes/index.js';
11
13
  export { createProvider } from './llm/provider-registry.js';
12
14
  export { resolveMaxOutputTokensPerLlmCall } from './schemas/config.schema.js';
13
15
  export { resolveScanStateBaseDir, resolveReportDir } from './harness/state-manager.js';
14
16
  export { NoopTelemetrySink } from './telemetry/telemetry.interface.js';
15
17
  export { redactUrlForTelemetry } from './telemetry/emit.js';
18
+ export { RecipeIdSchema } from './schemas/index.js';
19
+ // P3 — Confidence Layer exports
20
+ export { computeReleaseConfidence } from './tools/scoring/confidence.js';
21
+ // P4 — Evidence adapters (CI results + PR metadata)
22
+ export { ciResultsToEvidence } from './adapters/ci-results-adapter.js';
23
+ export { prMetadataToEvidence } from './adapters/pr-metadata-adapter.js';
24
+ export { buildConfidenceInputFromQulib } from './tools/scoring/confidence-from-qulib.js';
25
+ export { diffConfidence, deriveInbox, buildReplay, toAuditEntry } from './tools/scoring/confidence-views.js';
26
+ export { EvidenceSourceKindSchema, EvidenceItemSchema, ConfidenceSubjectSchema, ConfidenceInputSchema, ConfidencePolicySchema, ConfidenceVerdictSchema, ReleaseConfidenceSchema, } from './schemas/index.js';
@@ -0,0 +1,36 @@
1
+ /**
2
+ * a11y recipe — accessibility assertion patterns.
3
+ *
4
+ * Lifted from the PROVEN NQ-2 Playwright a11y suite and qulib's own axe-core
5
+ * integration in src/phases/accessibility.ts. Real patterns re-derived from
6
+ * first principles.
7
+ *
8
+ * NQ-2 Playwright a11y reference patterns:
9
+ * - import AxeBuilder from '@axe-core/playwright'
10
+ * - const results = await new AxeBuilder({ page }).analyze()
11
+ * - expect(violations.filter(v => v.impact === 'serious' || v.impact === 'critical')).toHaveLength(0)
12
+ * - await expect(page.locator('main')).toBeVisible()
13
+ * - await expect(page.locator('h1')).toBeVisible()
14
+ * - expect(await page.title()).not.toBe('')
15
+ *
16
+ * For Cypress (no axe-core adapter in the scaffold toolchain), we use:
17
+ * - Structural presence checks (h1, main, nav, [role=...])
18
+ * - Sufficient-contrast guards via role/aria-label checks
19
+ * - Focus-visible checks via keyboard nav simulation
20
+ */
21
+ import type { NeutralScenario } from '../schemas/gap-analysis.schema.js';
22
+ import type { RecipeConfig } from '../schemas/recipe.schema.js';
23
+ /**
24
+ * Generate NeutralScenarios for the a11y recipe.
25
+ *
26
+ * Returns 3 scenarios:
27
+ * 1. Page-level a11y — heading structure + landmark regions (all frameworks)
28
+ * 2. Interactive a11y — focus order / aria roles for primary CTA (smoke)
29
+ * 3. Image/text a11y — alt text presence + non-empty page title
30
+ *
31
+ * The Playwright adapter will render axe-core assertions for scenarios tagged
32
+ * 'a11y-axe'. The Cypress adapter renders structural/aria assertions (axe-core
33
+ * Cypress integration is out-of-scope for the scaffold toolchain today).
34
+ */
35
+ export declare function buildA11yScenarios(config?: RecipeConfig): NeutralScenario[];
36
+ //# sourceMappingURL=a11y.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"a11y.d.ts","sourceRoot":"","sources":["../../src/recipes/a11y.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAEhE;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,YAAiB,GAAG,eAAe,EAAE,CA6G/E"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Generate NeutralScenarios for the a11y recipe.
3
+ *
4
+ * Returns 3 scenarios:
5
+ * 1. Page-level a11y — heading structure + landmark regions (all frameworks)
6
+ * 2. Interactive a11y — focus order / aria roles for primary CTA (smoke)
7
+ * 3. Image/text a11y — alt text presence + non-empty page title
8
+ *
9
+ * The Playwright adapter will render axe-core assertions for scenarios tagged
10
+ * 'a11y-axe'. The Cypress adapter renders structural/aria assertions (axe-core
11
+ * Cypress integration is out-of-scope for the scaffold toolchain today).
12
+ */
13
+ export function buildA11yScenarios(config = {}) {
14
+ const impact = config.a11yImpact ?? 'serious';
15
+ return [
16
+ {
17
+ id: 'recipe-a11y-heading-structure',
18
+ title: 'Page has proper heading structure and landmark regions',
19
+ description: 'The root page has an H1 heading and at least one landmark region (main/nav/header/footer), providing a navigable document outline for screen-reader users',
20
+ targetPath: '/',
21
+ steps: [
22
+ { action: 'navigate', target: '/', description: 'Open the root page' },
23
+ {
24
+ action: 'assert-visible',
25
+ target: 'h1',
26
+ description: 'Page has an H1 heading (document outline)',
27
+ },
28
+ {
29
+ action: 'assert-visible',
30
+ target: 'main',
31
+ description: 'Page has a main landmark region',
32
+ },
33
+ {
34
+ action: 'assert-count',
35
+ target: 'nav',
36
+ value: '1',
37
+ description: 'At least one navigation landmark exists',
38
+ },
39
+ ],
40
+ tags: ['a11y', 'smoke', 'recipe-a11y', `a11y-impact-${impact}`],
41
+ recommendations: [
42
+ {
43
+ adapter: 'playwright',
44
+ reason: 'Landmark + heading assertions with Playwright locator — real NQ-2 pattern',
45
+ confidence: 'high',
46
+ },
47
+ {
48
+ adapter: 'cypress-e2e',
49
+ reason: 'Structural a11y assertions — cy.get on semantic elements',
50
+ confidence: 'high',
51
+ },
52
+ ],
53
+ sourceGapIds: ['recipe-a11y'],
54
+ },
55
+ {
56
+ id: 'recipe-a11y-interactive-aria',
57
+ title: 'Primary interactive elements have accessible names',
58
+ description: 'Buttons and links visible on the page carry accessible names (aria-label or text content), ensuring assistive technologies can identify the action',
59
+ targetPath: '/',
60
+ steps: [
61
+ { action: 'navigate', target: '/', description: 'Open the root page' },
62
+ {
63
+ action: 'assert-count',
64
+ target: 'button, a[href]',
65
+ value: '1',
66
+ description: 'At least one interactive element is present',
67
+ },
68
+ {
69
+ action: 'assert-visible',
70
+ target: 'button, [role=button]',
71
+ description: 'An accessible interactive element is visible on the page',
72
+ },
73
+ ],
74
+ tags: ['a11y', 'aria', 'recipe-a11y'],
75
+ recommendations: [
76
+ {
77
+ adapter: 'playwright',
78
+ reason: 'aria-label presence check — Playwright locator + toBeVisible',
79
+ confidence: 'medium',
80
+ },
81
+ {
82
+ adapter: 'cypress-e2e',
83
+ reason: 'Aria attribute presence — cy.get selector chain',
84
+ confidence: 'medium',
85
+ },
86
+ ],
87
+ sourceGapIds: ['recipe-a11y'],
88
+ },
89
+ {
90
+ id: 'recipe-a11y-page-title',
91
+ title: 'Page has a non-empty, descriptive document title',
92
+ description: 'The <title> element is non-empty — required for bookmarks, browser tabs, and screen-reader orientation',
93
+ targetPath: '/',
94
+ steps: [
95
+ { action: 'navigate', target: '/', description: 'Open the root page' },
96
+ {
97
+ action: 'assert-text',
98
+ target: 'title',
99
+ description: 'Document title element is non-empty',
100
+ },
101
+ ],
102
+ tags: ['a11y', 'seo', 'recipe-a11y'],
103
+ recommendations: [
104
+ {
105
+ adapter: 'playwright',
106
+ reason: 'page.title() !== "" — lightweight page-level a11y gate',
107
+ confidence: 'high',
108
+ },
109
+ {
110
+ adapter: 'cypress-e2e',
111
+ reason: 'cy.title().should("not.be.empty") — smoke a11y gate',
112
+ confidence: 'high',
113
+ },
114
+ ],
115
+ sourceGapIds: ['recipe-a11y'],
116
+ },
117
+ ];
118
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * auth recipe — login / logout / protected-route patterns.
3
+ *
4
+ * Lifted from the PROVEN NQ-2 Playwright specs and CaseLoom Cypress specs.
5
+ * These are REAL selector patterns and assertion patterns used in those test
6
+ * suites, re-derived from first principles (not copy-pasted).
7
+ *
8
+ * NQ-2 Playwright reference patterns:
9
+ * - page.goto('/login')
10
+ * - page.locator('[data-testid=login-email]').fill(email)
11
+ * - page.locator('[data-testid=login-password]').fill(password)
12
+ * - page.locator('[data-testid=login-submit]').click()
13
+ * - expect(page.locator('[data-testid=dashboard-root]')).toBeVisible()
14
+ * - expect(page.locator('[data-testid=login-error]')).toContainText('Invalid')
15
+ *
16
+ * CaseLoom Cypress reference patterns:
17
+ * - cy.visit('/login')
18
+ * - cy.get('[data-testid=login-email]').type(email)
19
+ * - cy.get('[data-testid=login-password]').type(password)
20
+ * - cy.get('[data-testid=login-submit]').click()
21
+ * - cy.get('[data-testid=dashboard-root]').should('be.visible')
22
+ * - cy.get('[data-testid=login-error]').should('contain.text', 'Invalid')
23
+ */
24
+ import type { NeutralScenario } from '../schemas/gap-analysis.schema.js';
25
+ import type { RecipeConfig } from '../schemas/recipe.schema.js';
26
+ /**
27
+ * Generate NeutralScenarios for the auth recipe.
28
+ *
29
+ * Returns 3 scenarios:
30
+ * 1. Happy-path login → lands on dashboard (smoke gate)
31
+ * 2. Invalid-credentials → inline error message shown (negative gate)
32
+ * 3. Protected route redirects unauthenticated users to login (security gate)
33
+ *
34
+ * All selectors come from the proven NQ-2/CaseLoom patterns and are overridable
35
+ * via RecipeConfig, so the recipe works for any form-login app.
36
+ */
37
+ export declare function buildAuthScenarios(config?: RecipeConfig): NeutralScenario[];
38
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/recipes/auth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAWhE;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,GAAE,YAAiB,GAAG,eAAe,EAAE,CA0I/E"}