# Bulk Claim Import Guide

**Problem:** Creating claims one-by-one via CLI is tedious. A 340-line shell script to import 22 claims is error-prone and obscures the actual claim data.

**Solution:** Use `aphoria claims import` to import claims in bulk from TOML files with validation, progress reporting, and merge strategies.

---

## Quick Start

### 1. Generate a Template

```bash
aphoria claims import --template > my-claims.toml
```

This creates an example TOML file with comprehensive inline documentation.

### 2. Edit the Template

Open `my-claims.toml` and replace the example claims with your own:

```toml
[[claim]]
id = "myapp-http-tls-cert-validation-001"
concept_path = "myapp/httpclient/tls/certificate_validation"
predicate = "enabled"
value = true
comparison = "equals"
provenance = "OWASP A02:2021 - Cryptographic Failures"
invariant = "HTTP clients MUST validate TLS certificates"
consequence = "Disabled validation exposes MITM attacks"
authority_tier = "regulatory"
evidence = ["OWASP Top 10", "CWE-295"]
category = "security"
status = "active"
created_by = "security-team"
created_at = "2024-12-15T10:00:00Z"
```

### 3. Validate

```bash
aphoria claims import my-claims.toml --validate-only
```

This checks your TOML format and field values **without** writing to `.aphoria/claims.toml`.

### 4. Preview

```bash
aphoria claims import my-claims.toml --dry-run
```

Shows what would be added, skipped, or overwritten.

### 5. Import

```bash
aphoria claims import my-claims.toml
```

Writes claims to `.aphoria/claims.toml` and displays a detailed report.

---

## TOML Format Reference

### Required Fields

Every claim must have these fields:

| Field | Type | Description | Example |
|-------|------|-------------|---------|
| `id` | string | Unique kebab-case identifier | `"myapp-feature-001"` |
| `concept_path` | string | Hierarchical path to concept | `"myapp/module/feature"` |
| `predicate` | string | Property being claimed | `"enabled"`, `"max_version"` |
| `value` | bool/number/string | Expected value | `true`, `50`, `"SeqCst"` |
| `comparison` | string | How to compare | `"equals"`, `"absent"` |
| `provenance` | string | Where this rule came from | `"Architecture decision by tech lead"` |
| `invariant` | string | What MUST remain true | `"Core MUST NOT import tokio"` |
| `consequence` | string | What breaks if violated | `"Makes library async-only"` |
| `authority_tier` | string | Authority level | `"expert"`, `"regulatory"` |
| `category` | string | Claim category | `"security"`, `"architecture"` |
| `created_by` | string | Author name | `"tech-lead"` |
| `created_at` | string | ISO 8601 timestamp | `"2024-12-15T10:00:00Z"` |

### Optional Fields

| Field | Type | Description | Default |
|-------|------|-------------|---------|
| `evidence` | array[string] | Supporting references | `[]` |
| `status` | string | `"active"`, `"deprecated"`, `"superseded"` | `"active"` |
| `supersedes` | string | ID of claim this replaces | (none) |
| `updated_at` | string | ISO 8601 timestamp | (none) |

### Comparison Modes

| Mode | Meaning | Example Use Case |
|------|---------|------------------|
| `equals` | Value must exactly match | `max_pool_size = 50` |
| `not_equals` | Value must differ | `log_level != "debug"` |
| `present` | Value must exist | `tls_config` present |
| `absent` | Value must not exist | `tokio` absent from imports |
| `contains` | Value must contain substring | Error message contains "timeout" |
| `not_contains` | Value must not contain substring | URL must not contain "http:" |

### Authority Tiers

From strongest to weakest:

1. **`regulatory`** - Legal/regulatory mandate (FDA, GDPR)
2. **`clinical`** - Peer-reviewed clinical evidence
3. **`observational`** - Real-world data, case studies
4. **`expert`** - Senior engineer/architect decision
5. **`community`** - Team consensus, convention
6. **`anecdotal`** - Individual experience, suggestion

---

## Import Modes

### Dry-Run Mode

Preview changes without writing to disk:

```bash
aphoria claims import my-claims.toml --dry-run
```

**Output:**
```
Aphoria Claims Import
========================================
🔍 Dry-run mode (no changes written)

Summary:
  Total claims in file:  22
  Added:                 18
  Skipped:               3
  Overwritten:           1

Details:
  ✓ ADD     httpclient-connect-timeout-001
  ⊗ SKIP    httpclient-tls-cert-validation-001 (already exists)
  ↻ UPDATE  aphoria-no-unwrap-001
```

### Validate-Only Mode

Check format and validity without importing:

```bash
aphoria claims import my-claims.toml --validate-only
```

**Success:**
```
✓ Validation passed
  Total claims: 22
  Warnings: 2

File is ready for import.
```

**Failure:**
```
❌ Validation Failed

Found 3 error(s) in import file:

  • Claim 'bad-id-001!' - id: Claim ID must be kebab-case (lowercase alphanumeric + hyphens): 'bad-id-001!'
  • Claim 'myapp-feature-001' - authority_tier: Unknown authority tier: 'super_expert'
  • Claim at index 5 - provenance: provenance cannot be empty

Fix these errors and try again.
```

---

## Merge Strategies

Control what happens when a claim ID already exists:

### Skip Existing (Default)

```bash
aphoria claims import my-claims.toml --merge skip_existing
```

- Adds new claims
- **Skips** claims with duplicate IDs
- Safe for re-running imports

### Overwrite

```bash
aphoria claims import my-claims.toml --merge overwrite
```

- Adds new claims
- **Replaces** existing claims with same ID
- Use when updating claims in bulk

### Fail on Duplicate

```bash
aphoria claims import my-claims.toml --merge fail_on_duplicate
```

- Adds new claims
- **Exits with error** if any ID exists
- Use for strict imports where duplicates indicate mistakes

---

## Output Formats

### Table Format (Default)

Human-readable output with symbols:

```bash
aphoria claims import my-claims.toml
```

**Output:**
```
Aphoria Claims Import
========================================
✓ Import Complete

Summary:
  Total claims in file:  22
  Added:                 18
  Skipped:               3
  Overwritten:           1

Details:
  ✓ ADD     httpclient-connect-timeout-001
  ✓ ADD     httpclient-request-timeout-001
  ⊗ SKIP    httpclient-tls-cert-validation-001 (already exists)
  ↻ UPDATE  aphoria-no-unwrap-001

Warnings:
  ⚠  httpclient-request-timeout-001: Duplicate concept_path
```

### JSON Format

Machine-readable output for tooling integration:

```bash
aphoria claims import my-claims.toml --format json
```

**Output:**
```json
{
  "summary": {
    "total_in_file": 22,
    "added": 18,
    "skipped": 3,
    "overwritten": 1,
    "failed": 0
  },
  "details": [
    {
      "action": "added",
      "claim_id": "httpclient-connect-timeout-001",
      "reason": null
    },
    {
      "action": "skipped",
      "claim_id": "httpclient-tls-cert-validation-001",
      "reason": "already exists"
    }
  ],
  "warnings": [
    "httpclient-request-timeout-001: Duplicate concept_path"
  ]
}
```

---

## Common Workflows

### Converting Shell Scripts to TOML

**Before:** 340-line shell script

```bash
#!/bin/bash
# create-claims.sh

aphoria claims create \
  --id httpclient-connect-timeout-001 \
  --concept-path "httpclient/config/connect_timeout" \
  --predicate "min_value" \
  --value "5000" \
  --comparison "equals" \
  --provenance "Load testing results 2024-12-10" \
  --invariant "Connect timeout MUST be at least 5 seconds" \
  --consequence "Shorter timeouts cause spurious errors" \
  --tier "expert" \
  --evidence "tests/http_tests.rs" \
  --category "networking" \
  --by "sre-team"

# Repeat 21 more times...
```

**After:** 200-line TOML file + 1-line command

```toml
# httpclient-claims.toml

[[claim]]
id = "httpclient-connect-timeout-001"
concept_path = "httpclient/config/connect_timeout"
predicate = "min_value"
value = 5000
comparison = "equals"
provenance = "Load testing results 2024-12-10"
invariant = "Connect timeout MUST be at least 5 seconds"
consequence = "Shorter timeouts cause spurious errors"
authority_tier = "expert"
evidence = ["tests/http_tests.rs"]
category = "networking"
status = "active"
created_by = "sre-team"
created_at = "2024-12-15T10:00:00Z"

# 21 more claims...
```

```bash
aphoria claims import httpclient-claims.toml
```

**Time saved:** 15 minutes → 1 second

### Importing from External Sources

When importing security standards or RFCs:

```bash
# Apply authority tier override
aphoria claims import owasp-top-10.toml \
  --authority-tier regulatory \
  --source-guide "OWASP Top 10 2021"
```

This:
- Overrides all `authority_tier` fields in the TOML
- Tracks the import in `.aphoria/ingested_guides.toml`
- Links imported claims to their source

### Updating Existing Claims

```bash
# Create updated claims file
cat > updates.toml <<'EOF'
[[claim]]
id = "myapp-pool-max-size-001"
# ... updated fields ...
EOF

# Apply updates
aphoria claims import updates.toml --merge overwrite
```

---

## Validation Rules

### ID Format

**Valid:**
- `myapp-feature-001`
- `http-tls-cert-validation`
- `core-no-tokio`

**Invalid:**
- `MyApp-Feature-001` (uppercase)
- `-myapp-feature` (leading hyphen)
- `myapp--feature` (consecutive hyphens)
- `myapp_feature` (underscores)
- Empty string
- Over 64 characters

### Required Field Validation

All fields must be non-empty strings (after trimming):
- `provenance`
- `invariant`
- `consequence`
- `category`
- `created_by`

### Authority Tier Validation

Must be one of: `regulatory`, `clinical`, `observational`, `expert`, `community`, `anecdotal`

### Duplicate Detection

**Errors:**
- Duplicate `id` within import file
- Duplicate `id` when using `--merge fail_on_duplicate`

**Warnings:**
- Duplicate `concept_path` + `predicate` combination
- `id` already exists in `.aphoria/claims.toml`

---

## Troubleshooting

### Parse Errors

**Error:** `Error parsing import file: TOML parse error at line 15, column 10`

**Fix:** Check TOML syntax. Common issues:
- Missing quotes around string values
- Unclosed brackets `[` or `]`
- Typo in field name (e.g., `categoey` instead of `category`)

### Validation Errors

**Error:** `Claim ID must be kebab-case`

**Fix:** Use lowercase letters, numbers, and hyphens only. No underscores, spaces, or uppercase.

**Error:** `Unknown authority tier: 'super_expert'`

**Fix:** Use one of the 6 valid tiers: regulatory, clinical, observational, expert, community, anecdotal.

### Import Conflicts

**Warning:** `Claim ID 'myapp-feature-001' already exists in claims file`

**Options:**
1. Use `--merge skip_existing` (default) - skips the duplicate
2. Use `--merge overwrite` - replaces the existing claim
3. Change the ID in your import file to make it unique

---

## Examples

See `applications/aphoria/examples/` for complete examples:

- **`import-template.toml`** - Template with comprehensive comments
- **`import-httpclient.toml`** - Real-world example (22 claims)

---

## Integration with Skills

The `/aphoria-claims` skill can generate bulk import files:

```bash
# After reviewing a PR diff, the skill generates:
cat > generated-claims.toml <<EOF
[[claim]]
id = "myapp-feature-new-001"
# ... full claim ...
EOF

# Import via CLI:
aphoria claims import generated-claims.toml
```

This enables:
1. **Skill analyzes diff** → identifies claimable patterns
2. **Skill generates TOML** → with full provenance
3. **Human reviews TOML** → edits if needed
4. **Human imports** → `aphoria claims import`

---

## Performance

**Bulk import vs. Individual creates:**

| Task | Shell Script (22 claims) | Bulk Import |
|------|--------------------------|-------------|
| Lines of code | 340 | 200 |
| Execution time | ~15 minutes | < 1 second |
| Validation | 0% (manual review) | 100% (pre-import) |
| Error reporting | First error only | All errors at once |
| Rollback | Partial writes | Atomic (all or nothing) |

---

## See Also

- [Claims Guide](./claims.md) - Understanding claims vs observations
- [Getting Started](../getting-started/README.md) - Initial setup
- [CLI Reference](../README.md) - All commands
