## Spec-Driven Tests

`openlore test` reports which OpenSpec scenarios have corresponding tests. Tests are written by AI agent skills — not auto-generated — so every assertion is real.

### Writing tests

Use the `openlore-write-tests` skill to write tests for a function or spec scenario. The skill reads the implementation and spec contract first, absorbs the local test conventions, writes real assertions, runs and fixes failures, then reports coverage.

```
Vibe:  /openlore-write-tests
Cline: .clinerules/workflows/openlore-write-tests.md
```

The skill is language-agnostic (TypeScript, Python, C++, Go) and detects the test framework automatically (vitest, pytest, gtest, …). Each written test carries an annotation tag so coverage tracking works:

```typescript
// openlore: {"domain":"auth","requirement":"UserLogin","scenario":"SuccessfulLogin","specFile":"openspec/specs/auth/spec.md"}
describe("Auth / UserLogin / SuccessfulLogin", () => {
  it("should return a JWT token and userId with status 200", async () => {
    const response = await loginUser({ email: "alice@test.com", password: "valid" });
    expect(response.status).toBe(200);
    expect(response.body).toHaveProperty("token");
    expect(response.body).toHaveProperty("userId");
  });
});
```

```python
# openlore: {"domain":"auth","requirement":"UserLogin","scenario":"SuccessfulLogin"}
class TestLogin:
    def test_returns_jwt_token_with_status_200(self):
        response = client.post("/auth/login", json={"email": "alice@test.com", "password": "valid"})
        assert response.status_code == 200
        assert "token" in response.json()
```

The `// openlore:` tag is location-independent — move the test to any file and coverage tracking still works.

### Spec Coverage

```bash
$ openlore test --coverage

   Spec Test Coverage Report
   ─────────────────────────────────────────

   Total scenarios:    24
   Covered (tagged):   16
   Uncovered:           8
   Effective coverage: 66.7%  (target: 80%) ✗ below threshold

   By domain:
     auth                   5/6   (83%) ✓
     tasks                  4/6   (67%) ⚠ drift detected
     projects               7/8   (87%) ✓
     database               0/4    (0%) — no tests yet

   Uncovered scenarios:
     auth/UserLogin/MissingFields
     tasks/CreateTask/DuplicateTitle
     ...
```

Domains with active drift issues are flagged — prioritize writing tests there first.

### Coverage Options

```bash
openlore test [options]
  --domains <list>         Only report on specific domains (comma-separated)
  --min-coverage <n>       Fail if effective coverage is below N% (CI gate)
  --discover               Semantic discovery of tests without annotation tags (requires --use-llm)
  --use-llm                Enable LLM for --discover
  --test-dirs <list>       Directories to scan (default: spec-tests,src)
  --json                   Machine-readable JSON output
```

## Spec Digest

Specs are written for machines — `### Requirement:` / `#### Scenario:` / `- **GIVEN**` / `- **WHEN**` / `- **THEN**`. The format is intentional and powers all the tooling. But it makes human review tedious.

`openlore digest` reads your existing spec files and renders them as plain English — one line per scenario, no boilerplate. Source files are never touched.

```bash
openlore digest                        # Print to stdout
openlore digest --save                 # Write to openspec/digest.md
openlore digest --output review.md     # Write to a custom path
openlore digest --domains auth,payment # Only selected domains
```

Example output:

```markdown
# Spec Digest

_3 domains · 8 requirements · 21 scenarios_

> Auto-generated by `openlore digest`. Source specs are unchanged.

## Auth

Handles login, logout, and session management.

**Login**

- **ValidCredentials**: User submits valid credentials → session token returned.
- **InvalidCredentials**: Invalid credentials submitted → 401 with error message.

**PasswordReset**

- **TokenRequested**: User requests a password reset → email sent with time-limited token.
- **TokenExpired**: An expired reset token is used → request rejected with clear message.

## Payment

Processes charges and manages billing state.

**Checkout**

- **Success**: Valid card and basket submitted → charge created, order confirmed.
- **DeclinedCard**: Declined card submitted → order rejected, user notified.
```

No API key required. Fast and deterministic.

