Metadata-Version: 2.4
Name: qalens
Version: 0.1.1
Summary: QA Lens: turn static test reports into triage-ready intelligence
Project-URL: Homepage, https://github.com/Arulprasath36/QALens
Project-URL: Documentation, https://github.com/Arulprasath36/QALens/tree/main/docs
Project-URL: Repository, https://github.com/Arulprasath36/QALens
Project-URL: Issues, https://github.com/Arulprasath36/QALens/issues
Project-URL: Changelog, https://github.com/Arulprasath36/QALens/releases
Author: QA Lens Contributors
License:                                  Apache License
                                   Version 2.0, January 2004
                                http://www.apache.org/licenses/
        
           TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
        
           1. Definitions.
        
              "License" shall mean the terms and conditions for use, reproduction,
              and distribution as defined by Sections 1 through 9 of this document.
        
              "Licensor" shall mean the copyright owner or entity authorized by
              the copyright owner that is granting the License.
        
              "Legal Entity" shall mean the union of the acting entity and all
              other entities that control, are controlled by, or are under common
              control with that entity. For the purposes of this definition,
              "control" means (i) the power, direct or indirect, to cause the
              direction or management of such entity, whether by contract or
              otherwise, or (ii) ownership of fifty percent (50%) or more of the
              outstanding shares, or (iii) beneficial ownership of such entity.
        
              "You" (or "Your") shall mean an individual or Legal Entity
              exercising permissions granted by this License.
        
              "Source" form shall mean the preferred form for making modifications,
              including but not limited to software source code, documentation
              source, and configuration files.
        
              "Object" form shall mean any form resulting from mechanical
              transformation or translation of a Source form, including but
              not limited to compiled object code, generated documentation,
              and conversions to other media types.
        
              "Work" shall mean the work of authorship made available under
              the License, as indicated by a copyright notice that is included in
              or attached to the work (an example is provided in the Appendix below).
        
              "Derivative Works" shall mean any work, whether in Source or Object
              form, that is based on (or derived from) the Work and for which the
              editorial revisions, annotations, elaborations, or other transformations
              represent, as a whole, an original work of authorship. For the purposes
              of this License, Derivative Works shall not include works that remain
              separable from, or merely link (or bind by name) to the interfaces of,
              the Work and Derivative Works thereof.
        
              "Contribution" shall mean, as submitted to the Licensor for inclusion
              in the Work by the copyright owner or by an individual or Legal Entity
              authorized to submit on behalf of the copyright owner. For the purposes
              of this definition, "submitted" means any form of electronic, verbal,
              or written communication sent to the Licensor or its representatives,
              including but not limited to communication on electronic mailing lists,
              source code control systems, and issue tracking systems that are managed
              by, or on behalf of, the Licensor for the purpose of developing and
              coordinating the Work, but excluding communication that is
              conspicuously marked or otherwise designated in writing by the copyright
              owner as "Not a Contribution."
        
              "Contributor" shall mean Licensor and any Legal Entity on behalf of
              whom a Contribution has been received by the Licensor and included
              within the Work.
        
           2. Grant of Copyright License. Subject to the terms and conditions of
              this License, each Contributor hereby grants to You a perpetual,
              worldwide, non-exclusive, no-charge, royalty-free, irrevocable
              copyright license to reproduce, prepare Derivative Works of,
              publicly display, publicly perform, sublicense, and distribute the
              Work and such Derivative Works in Source or Object form.
        
           3. Grant of Patent License. Subject to the terms and conditions of
              this License, each Contributor hereby grants to You a perpetual,
              worldwide, non-exclusive, no-charge, royalty-free, irrevocable
              (except as stated in this section) patent license to make, have made,
              use, offer to sell, sell, import, and otherwise transfer the Work,
              where such license applies only to those patent claims licensable
              by such Contributor that are necessarily infringed by their
              Contribution(s) alone or by the combination of their Contribution(s)
              with the Work to which such Contribution(s) was submitted. If You
              institute patent litigation against any entity (including a
              cross-claim or counterclaim in a lawsuit) alleging that the Work
              or a Contribution incorporated within the Work constitutes direct
              or contributory patent infringement, then any patent licenses
              granted to You under this License for that Work shall terminate
              as of the date such litigation is filed.
        
           4. Redistribution. You may reproduce and distribute copies of the
              Work or Derivative Works thereof in any medium, with or without
              modifications, and in Source or Object form, provided that You
              meet the following conditions:
        
              (a) You must give any other recipients of the Work or Derivative
                  Works a copy of this License; and
        
              (b) You must cause any modified files to carry prominent notices
                  stating that You changed the files; and
        
              (c) You must retain, in the Source form of any Derivative Works
                  that You distribute, all copyright, patent, trademark, and
                  attribution notices from the Source form of the Work,
                  excluding those notices that do not pertain to any part of
                  the Derivative Works; and
        
              (d) If the Work includes a "NOTICE" text file as part of its
                  distribution, You must include a readable copy of the
                  attribution notices contained within such NOTICE file, in
                  at least one of the following places: within a NOTICE text
                  file distributed as part of the Derivative Works; within
                  the Source form or documentation, if provided along with the
                  Derivative Works; or, within a display generated by the
                  Derivative Works, if and wherever such third-party notices
                  normally appear. The contents of the NOTICE file are for
                  informational purposes only and do not modify the License.
                  You may add Your own attribution notices within Derivative
                  Works that You distribute, alongside or in addition to the
                  NOTICE text from the Work, provided that such additional
                  attribution notices cannot be construed as modifying the License.
        
              You may add Your own license statement for Your modifications and
              may provide additional grant of rights to use, copy, modify, merge,
              publish, distribute, sublicense, and/or sell copies of the
              contribution, and to represent that it is original work, consistent
              with its role in general open source software practices.
        
           5. Submission of Contributions. Unless You explicitly state otherwise,
              any Contribution intentionally submitted for inclusion in the Work
              by You to the Licensor shall be under the terms and conditions of
              this License, without any additional terms or conditions.
              Notwithstanding the above, nothing herein shall supersede or modify
              the terms of any separate license agreement you may have executed
              with Licensor regarding such Contributions.
        
           6. Trademarks. This License does not grant permission to use the trade
              names, trademarks, service marks, or product names of the Licensor,
              except as required for reasonable and customary use in describing the
              origin of the Work and reproducing the content of the NOTICE file.
        
           7. Disclaimer of Warranty. Unless required by applicable law or
              agreed to in writing, Licensor provides the Work (and each
              Contributor provides its Contributions) on an "AS IS" BASIS,
              WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
              implied, including, without limitation, any warranties or conditions
              of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
              PARTICULAR PURPOSE. You are solely responsible for determining the
              appropriateness of using or reproducing the Work and assume any
              risks associated with Your exercise of permissions under this License.
        
           8. Limitation of Liability. In no event and under no legal theory,
              whether in tort (including negligence), contract, or otherwise,
              unless required by applicable law (such as deliberate and grossly
              negligent acts) or agreed to in writing, shall any Contributor be
              liable to You for damages, including any direct, indirect, special,
              incidental, or exemplary damages of any character arising as a
              result of this License or out of the use or inability to use the
              Work (including but not limited to damages for loss of goodwill,
              work stoppage, computer failure or malfunction, or all other
              commercial damages or losses), even if such Contributor has been
              advised of the possibility of such damages.
        
           9. Accepting Warranty or Additional Liability. While redistributing
              the Work or Derivative Works thereof, You may choose to offer,
              and charge a fee for, acceptance of support, warranty, indemnity,
              or other liability obligations and/or rights consistent with this
              License. However, in accepting such obligations, You may offer only
              conditions consistent with this License, provided that You include
              terms and conditions that clearly describe the terms of the
              indemnity or warranty and disclaim any implied warranties.
        
           END OF TERMS AND CONDITIONS
        
           APPENDIX: How to apply the Apache License to your work.
        
              To apply the Apache License to your work, attach the following
              boilerplate notice, with the fields enclosed by brackets "[]"
              replaced with your own identifying information. (Don't include
              the brackets!)  The text should be enclosed in the appropriate
              comment syntax for the file format in question. It also should be
              formatted correctly to be readable by humans.
        
           Copyright 2026 QA Lens Contributors
        
           Licensed under the Apache License, Version 2.0 (the "License");
           you may not use this file except in compliance with the License.
           You may obtain a copy of the License at
        
               http://www.apache.org/licenses/LICENSE-2.0
        
           Unless required by applicable law or agreed to in writing, software
           distributed under the License is distributed on an "AS IS" BASIS,
           WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
           See the License for the specific language governing permissions and
           limitations under the License.
License-File: LICENSE
Keywords: QA,allure,extent reports,failure analysis,flaky tests,root cause analysis,test automation,test reporting
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Quality Assurance
Classifier: Topic :: Software Development :: Testing
Classifier: Typing :: Typed
Requires-Python: >=3.10
Requires-Dist: beautifulsoup4>=4.12
Requires-Dist: defusedxml>=0.7.1
Requires-Dist: fastapi>=0.110
Requires-Dist: httpx>=0.27
Requires-Dist: lxml>=6.1.0
Requires-Dist: pydantic>=2.5
Requires-Dist: python-dateutil>=2.8
Requires-Dist: python-multipart>=0.0.27
Requires-Dist: rich>=13.0
Requires-Dist: tomli>=2.0; python_version < '3.11'
Requires-Dist: typer>=0.12
Requires-Dist: uvicorn>=0.29
Provides-Extra: dev
Requires-Dist: hatch>=1.12; extra == 'dev'
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pre-commit>=3.7; extra == 'dev'
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
Requires-Dist: pytest-httpx>=0.30; extra == 'dev'
Requires-Dist: pytest>=9.0.3; extra == 'dev'
Requires-Dist: ruff>=0.4; extra == 'dev'
Requires-Dist: types-beautifulsoup4; extra == 'dev'
Requires-Dist: types-python-dateutil; extra == 'dev'
Provides-Extra: ml
Requires-Dist: numpy>=1.26; extra == 'ml'
Requires-Dist: scikit-learn>=1.4; extra == 'ml'
Description-Content-Type: text/markdown

# QA Lens

> Turn existing test automation reports into local, explainable triage intelligence.

[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
[![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)](https://www.python.org/)
[![PyPI](https://img.shields.io/badge/pypi-qalens-blue.svg)](https://pypi.org/project/qalens/)

<p align="center">
  <img src="https://raw.githubusercontent.com/Arulprasath36/QALens/main/docs/assets/qa-lens-dashboard.png" alt="QA Lens dashboard" width="720">
</p>

---

## What is QA Lens?

QA Lens reads the HTML or XML reports your test framework already produces, stores the results in a local SQLite database, and helps answer questions your report viewer does not:

- What failed in the latest run, and why?
- Which failures are related and share the same root cause?
- Which tests are flaky — and is the flakiness getting worse?
- Which tests are highest risk of failing in the next run?
- Is the suite trending healthier or degrading over time?
- What should the team look at first?

**QA Lens is not a test runner.** It does not replace Allure, Extent, Playwright, Cypress, JUnit, or TestNG. It is an analysis and intelligence layer on top of those reports.

---

## Why QA Lens?

Modern test suites produce hundreds or thousands of results per run. Existing report tools show pass/fail status, logs, screenshots, and stack traces — and stop there.

| Problem | What QA Lens does |
|---|---|
| Hours spent manually triaging failures | Automates failure classification and root-cause grouping |
| "Is this flaky or a real bug?" | Scores flakiness across multiple runs using history |
| "Is infra to blame or the product?" | Categories: environment, test script, product defect, test data |
| "We keep seeing the same failure pattern" | Groups failures by normalized signature across runs |
| "What do I tell the engineering lead?" | Generates concise decision summaries and priority actions |
| "Is the suite getting better or worse?" | Tracks trends, pass rates, and test stability over time |

---

## Key Features

- **CLI:** `qalens` — ingest, analyze, compare, ask, report
- **Web UI:** runs, incidents, analysis trends, risk, comparison, LLM chat, settings
- **Deterministic analysis** — failure classification, clustering, risk scoring, and many answers require no LLM
- **SQLite-backed run history** — lightweight, portable, no separate database server
- **Owner mapping** — assign tests to teams; track failure rates per owner
- **Multi-format parsing** — Allure, Extent, JUnit, TestNG, Playwright, Cypress/Mocha
- **Shareable reports** — standalone HTML, Markdown, and JSON export
- **Optional LLM chat** — local (Ollama) or cloud providers, explicitly opt-in
- **Optional auth** — token or GitHub OAuth; off by default for local use

---

## Supported Report Formats

| Format | Supported input |
|---|---|
| Allure | HTML report folders with JSON data (v2) |
| Extent | HTML reports (v4, v5) |
| JUnit | `testsuite` / `testsuites` XML |
| TestNG | `testng-results.xml` |
| Playwright | JSON reports and JSON-backed HTML report folders |
| Cypress / Mocha | JSON reports, including Mochawesome-style output |

---

## Installation

### From PyPI (recommended)

```bash
pip install qalens
```

This installs the `qalens` CLI with the web UI already bundled. No Node.js required.

Verify:

```bash
qalens --version
qalens --help
```

### From source

Required: Python 3.10+, Node.js 18+, npm, Git.

```bash
git clone https://github.com/Arulprasath36/QALens.git
cd QALens

python3 -m venv .venv
source .venv/bin/activate          # macOS / Linux
# .\.venv\Scripts\Activate.ps1    # Windows PowerShell

pip install -e .

# Build the web UI (required when installing from source)
make build-ui
```

For development (adds pytest, ruff, mypy):

```bash
pip install -e ".[dev]"
```

Verify:

```bash
qalens --version
qalens --help
```

---

## Quick Start

### 1 — Ingest a sample report

QA Lens ships with sample fixtures for every supported format:

```bash
qalens ingest tests/fixtures/allure_sample --db ./qalens.db
```

Or ingest your own report:

```bash
qalens ingest path/to/your-allure-report --db ./qalens.db
```

### 2 — Start the web UI

```bash
qalens serve --db ./qalens.db
```

Open `http://127.0.0.1:8080` in your browser.

### 3 — Ask a question

```bash
qalens ask "What broke in the latest run?" --db ./qalens.db
qalens ask "Which tests are flaky?" --db ./qalens.db
```

Many questions are answered deterministically from the database — no LLM required.

---

## CLI Reference

### Detect report format

```bash
qalens detect path/to/report
```

### Extract normalized JSON (no database)

```bash
qalens extract path/to/report --out extracted.json
```

### Ingest a report into the database

```bash
qalens ingest path/to/report --db ./qalens.db
qalens ingest path/to/report --db ./qalens.db --owner-map owners.toml
```

If you haven't ingested any reports yet, ingest at least one so the UI has something to show.

### Analyze stored runs

```bash
qalens analyze --db ./qalens.db
```

### Compare run history

```bash
qalens compare --db ./qalens.db --by runs --window 10
qalens compare --db ./qalens.db --by owners --window 10
qalens compare --db ./qalens.db --by suites --window 10
qalens compare --db ./qalens.db --by modules --window 10
```

Use `--run-id RUN_A --run-id RUN_B` for an explicit range.

### Inspect one target over time

```bash
qalens history test "testCreditCardPayment()" --db ./qalens.db
qalens history owner "Checkout Team" --db ./qalens.db
qalens history suite "Payments" --db ./qalens.db
qalens history failure FINGERPRINT --db ./qalens.db
```

### Generate a standalone report

```bash
qalens report --db ./qalens.db --out report.html
qalens report --db ./qalens.db --format markdown --out report.md
qalens report --db ./qalens.db --format json --out report.json
```

### One-off summary (no database)

```bash
qalens summarize path/to/report --format markdown --out summary.md
qalens clusters path/to/report
```

---

## Demo Dataset

The repo includes a synthetic 53-run ShopNow E-Commerce dataset:

```text
tmp_test_data/ShopNow_E-Commerce/run_001/ … run_053/
```

Build a demo database:

```bash
for report in tmp_test_data/ShopNow_E-Commerce/run_*; do
  qalens ingest "$report" --db ./shopnow-demo.db
done
```

Explore it:

```bash
qalens serve --db ./shopnow-demo.db
qalens analyze --db ./shopnow-demo.db
qalens report --db ./shopnow-demo.db --out shopnow-report.html
```

---

## Web UI

Start the server:

```bash
qalens serve                        # uses ~/.qalens/qalens.db by default
qalens serve --db ./qalens.db       # project-local database
qalens serve --port 9090            # custom port (default: 8080)
```

| Tab | What it shows |
|---|---|
| Runs | Latest run results, decision brief, fix-first actions, and per-test details |
| Incidents | Recurring failure signatures and root-cause clusters |
| Analysis | Suite health trends, pass-rate chart, owner load, active clusters |
| Risk | Tests most likely to fail or flip in the next run |
| Compare | Side-by-side comparison of runs, owners, suites, or modules |
| Chat | Ask questions — answered deterministically or via LLM |
| Settings | Runtime paths, LLM config, authentication status (admin only) |

### Frontend development mode

Run the API and Vite dev server in two terminals for hot-reload:

```bash
# Terminal 1
qalens serve --db ./qalens.db --no-open

# Terminal 2
cd frontend && npm run dev
```

Open `http://localhost:3000` — API requests are proxied to port 8080.

---

## Deterministic vs LLM-Assisted

QA Lens works without an LLM for all of the following:

- Ingesting reports and storing results
- Failure classification (environment / test script / product defect / test data / flaky / unknown)
- Failure clustering by normalized signature
- Run comparison and regression detection
- Risk tier scoring
- Flakiness signals
- Shareable report export
- Trend analysis and suite health in the web UI
- Many factual `qalens ask` questions

LLM-assisted answers are useful for open-ended questions and explanations. They require a configured provider and are always opt-in.

---

## LLM Setup (Optional)

QA Lens does not ship or install any LLM. It connects to one you provide.

Create the config file:

```bash
qalens llm-config --init
qalens llm-config --show
```

The default config points to a locally-running [Ollama](https://ollama.com) instance, which you install and run separately. If Ollama is not running, LLM-assisted chat is unavailable — all other features remain fully functional.

LLM settings can also be changed in the web UI under **Settings → LLM** without editing the config file.

### Cloud providers (opt-in)

Cloud providers send report data (test names, stack traces, error messages) to an external service. Enable them explicitly only after reviewing what data may leave your machine.

**Via the Settings page** (easiest): open the web UI → Settings → choose a provider → enable **Allow external LLM**.

**Via `~/.qalens/config.toml`:**

```toml
[llm]
provider = "openai"
allow_external = true
```

**Via environment variable:**

```bash
export QALENS_ALLOW_EXTERNAL_LLM=1
```

---

## Authentication

By default, `qalens serve` binds to `127.0.0.1` and requires no login.

### Token-based access

```bash
export QALENS_AUTH_TOKEN="replace-with-a-long-random-token"
qalens serve --db ./qalens.db --host 0.0.0.0 --allow-public-bind
```

Or for a single session:

```bash
qalens serve --db ./qalens.db --auth-token "replace-with-a-long-random-token"
```

### GitHub OAuth

```bash
export QALENS_AUTH_MODE=github
export QALENS_GITHUB_CLIENT_ID="your-client-id"
export QALENS_GITHUB_CLIENT_SECRET="your-client-secret"
export QALENS_SESSION_SECRET="$(openssl rand -base64 32)"   # keep stable across restarts
export QALENS_ALLOWED_GITHUB_USERS="your-github-login,teammate"
export QALENS_ALLOWED_GITHUB_ORGS="your-org"               # optional: grant whole org
export QALENS_ADMIN_GITHUB_USERS="your-github-login"        # optional: restrict Settings tab

qalens serve --db ./qalens.db
```

**Creating the GitHub OAuth App:**

1. Go to [github.com/settings/developers](https://github.com/settings/developers)
2. Click **OAuth Apps → New OAuth App**
3. Fill in:

   | Field | Value |
   |---|---|
   | Application name | `QA Lens` |
   | Homepage URL | `http://localhost:8080` |
   | Authorization callback URL | `http://localhost:8080/auth/github/callback` |

4. Click **Register application**
5. Copy the **Client ID** → `QALENS_GITHUB_CLIENT_ID`
6. Click **Generate a new client secret** → copy immediately (shown once) → `QALENS_GITHUB_CLIENT_SECRET`

For production, replace `http://localhost:8080` with your HTTPS URL in both fields, or set `QALENS_GITHUB_CALLBACK_URL` explicitly.

**Sessions and sign-out:** Sessions last 8 hours. Use the same `QALENS_SESSION_SECRET` across server restarts to avoid invalidating active sessions. Users sign out via the **Sign out** button at the bottom of the sidebar.

**Admin access:** By default every authenticated GitHub user can access the Settings panel. Set `QALENS_ADMIN_GITHUB_USERS` to a comma-separated list of logins to restrict it. Non-admin users see all analysis views; the Settings tab is hidden and the settings API returns 403.

For networked deployments, use HTTPS and review [SECURITY.md](SECURITY.md) and [PRODUCTION_CHECKLIST.md](PRODUCTION_CHECKLIST.md).

---

## Database

Default location:

```text
~/.qalens/qalens.db
```

Use a project-local database with `--db`:

```bash
qalens ingest path/to/report --db ./qalens.db
qalens serve --db ./qalens.db
```

The database is a standard SQLite file. Back it up by copying the file. The web UI, history, comparison, trends, and report export all read from it.

---

## Owner Mapping

If reports do not include team ownership, provide a mapping at ingestion:

```bash
qalens ingest path/to/report --db ./qalens.db --owner-map owners.toml
```

Example `owners.toml`:

```toml
[[owners]]
owner = "Authentication Team"
suites = ["Authentication*"]
tags = ["auth", "login"]

[[owners]]
owner = "Checkout Team"
features = ["Checkout", "Payments"]
tests = ["testPayPal*", "testCreditCardPayment()"]

[[owners]]
owner = "Search Team"
test_regex = ["Search.*Filter"]
```

Rules match on `tests`, `canonical_tests`, `test_regex`, `suites`, `features`, `stories`, and `tags`. Existing owner labels from the report are preserved unless you pass `--override-owners`.

---

## Screenshot and Artifact Handling

QA Lens is text-first. Screenshots are optional supporting evidence.

| Mode | What is stored |
|---|---|
| `text-only` | Test names, statuses, errors, and stack traces only |
| `metadata-only` *(default)* | Plus screenshot hashes, dimensions, MIME types, and references — no image bytes |
| `full` | Plus image bytes in a configurable artifact directory |

```bash
qalens ingest ./report --artifact-mode text-only
qalens ingest ./report --artifact-mode full --artifact-storage-dir ~/.qalens/artifacts
```

Image bytes are never stored in the SQLite database.

---

## Security Defaults

QA Lens treats reports as untrusted input:

- Report file type validation
- Raster image validation by magic bytes (not filename extension)
- SVG artifact rejection
- Common secret redaction before LLM submission
- No telemetry or outbound calls by default
- Cloud LLM providers disabled unless explicitly allowed

See [SECURITY.md](SECURITY.md) for the full security policy and vulnerability reporting instructions.

---

## Python API

```python
from qalens.api.library import QALensClient

client = QALensClient()

report_type = client.detect_report("./reports/allure-report")
run = client.extract_report("./reports/allure-report")
analysis = client.analyze_report(run)

summary = client.summarize_report(analysis, fmt="markdown")
print(summary)
```

---

## Repository Structure

```text
QALens/
├── src/qalens/              # Python package
│   ├── api/                 # Public Python API (QALensClient)
│   ├── analyzers/           # Classification, clustering, flaky, risk, decision
│   ├── artifacts/           # Screenshot policy and artifact storage
│   ├── cli/                 # CLI commands (ingest, serve, compare, …)
│   ├── db/                  # SQLite schema and repository layer
│   ├── llm/                 # LLM config, prompts, client
│   ├── parsers/             # Allure, Extent, JUnit, TestNG, Playwright, Cypress
│   ├── reports/             # HTML/Markdown/JSON report builders
│   ├── server/              # FastAPI app, routes, auth, static UI
│   └── utils/               # Filesystem and text helpers
├── frontend/                # React + Vite web UI source
├── tests/                   # Python test suite
│   └── fixtures/            # Sample reports for all supported formats
├── docs/                    # Architecture and design documentation
├── tmp_test_data/           # Synthetic ShopNow demo dataset
├── Makefile                 # Build shortcuts
├── pyproject.toml           # Python package metadata
├── SECURITY.md              # Security policy
└── PRODUCTION_CHECKLIST.md  # Network deployment checklist
```

### Build commands

| Command | What it does |
|---|---|
| `make build-ui` | Compile React app into `src/qalens/server/static/` |
| `make build` | `build-ui` + build the Python wheel |
| `make check-package` | Build distributions and run `twine check` |
| `make release-test` | Build, check, and publish to TestPyPI |
| `make release` | Build, check, and publish to PyPI |

### Publishing to PyPI

The package name is `qalens`; the CLI command is also `qalens`.

Recommended release flow:

```bash
# 1. Make sure the version in src/qalens/version.py is final.

# 2. Run local verification.
pytest
cd frontend && npm test -- --run && npm audit --audit-level=high && cd ..
pip-audit --desc
bandit -r src/ -ll -x src/qalens/server/static/

# 3. Build and validate distributions.
make check-package

# 4. Publish to TestPyPI first.
make release-test

# 5. Install from TestPyPI in a clean environment and smoke test.
python -m venv /tmp/qalens-smoke
source /tmp/qalens-smoke/bin/activate
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ qalens
qalens --help

# 6. Publish to PyPI.
make release
```

For GitHub-based publishing, use the `Publish Python package` workflow and configure PyPI/TestPyPI Trusted Publishing for the matching GitHub environments.

---

## Limitations

- QA Lens does not execute tests.
- Single-run data is sufficient for basic failure summaries. Trends, risk scoring, and flakiness detection improve with more ingested runs.
- LLM-assisted answers require a configured provider. Deterministic answers do not.
- Parser accuracy depends on the data exported by the report tool. Reports that omit stack traces or error types reduce classification confidence.
- The web server is local-first. Do not expose it publicly without authentication, HTTPS, and network controls.
- Repository-wide strict `ruff` / `mypy` / `bandit` cleanup is in progress.

---

## Roadmap

Near-term:

- More real-world report fixtures and edge-case coverage
- CI quality gate cleanup (ruff, mypy, bandit)
- Screenshots and demo video
- More export formats and CI integration examples

See [docs/roadmap.md](docs/roadmap.md).

---

## Contributing

Contributions are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md) first.

Local checks:

```bash
pytest
cd frontend && npm run typecheck && npm test
```

---

## License

[Apache 2.0](LICENSE)
