Status: Draft · Date: 2025-12-04 Scope: Standardize retry/backoff/error taxonomy for the competitor ingest pipeline with deterministic diagnostics.
- Define comprehensive error taxonomy for ingest failures.
- Specify retry behavior for transient errors.
- Enable deterministic error diagnostics.
- Support offline error handling.
| Code | Category | Description | Max Retries | Backoff |
|---|
E1001 | network_error | Network connectivity failure | 3 | Exponential |
E1002 | network_timeout | Connection/read timeout | 3 | Exponential |
E1003 | rate_limit | Rate limit exceeded (429) | 5 | Linear |
E1004 | service_unavailable | Service temporarily unavailable (503) | 3 | Exponential |
E1005 | transient_io | Temporary I/O error | 2 | Fixed |
E1006 | lock_contention | Resource lock conflict | 3 | Exponential |
| Code | Category | Description | Action |
|---|
E2001 | signature_invalid | Signature verification failed | Reject |
E2002 | signature_expired | Signature validity exceeded | Reject |
E2003 | key_unknown | Signing key not found | Reject |
E2004 | key_expired | Signing key validity exceeded | Reject |
E2005 | key_revoked | Signing key revoked | Reject |
E2006 | alg_unsupported | Unsupported algorithm | Reject |
E2007 | hash_mismatch | Content hash mismatch | Reject |
E2008 | schema_invalid | Input doesn’t match schema | Reject |
E2009 | version_unsupported | Tool version not supported | Reject |
E2010 | no_evidence | No acceptable evidence found | Reject |
| Code | Category | Description | Action |
|---|
W3001 | provenance_unknown | Provenance not verifiable | Accept with warning |
W3002 | degraded_confidence | Low confidence result | Accept with warning |
W3003 | stale_data | Data exceeds freshness threshold | Accept with warning |
W3004 | partial_mapping | Some fields couldn’t be mapped | Accept with warning |
W3005 | deprecated_format | Using deprecated format | Accept with warning |
{
"error": {
"code": "E2001",
"category": "signature_invalid",
"message": "DSSE signature verification failed",
"details": {
"reason": "Key ID not found in trusted keyring",
"keyId": "unknown-key-12345",
"algorithm": "ecdsa-p256"
},
"retryable": false,
"diagnostics": {
"timestamp": "2025-12-04T12:00:00Z",
"traceId": "abc123...",
"inputHash": "b3:...",
"stage": "signature_verification"
}
}
}
{
"result": {
"status": "accepted_with_warnings",
"warnings": [
{
"code": "W3001",
"category": "provenance_unknown",
"message": "SBOM accepted without verified provenance",
"details": {
"reason": "No signature present",
"fallbackLevel": 2
}
}
],
"output": {...}
}
}
{
"backoff": {
"exponential": {
"description": "2^attempt * base, capped at max",
"config": {
"base": 1000,
"factor": 2,
"max": 60000,
"jitter": 0.1
},
"example": [1000, 2000, 4000, 8000, 16000, 32000, 60000]
},
"linear": {
"description": "initial + (attempt * increment), capped at max",
"config": {
"initial": 1000,
"increment": 1000,
"max": 30000
},
"example": [1000, 2000, 3000, 4000, 5000]
},
"fixed": {
"description": "Constant delay between retries",
"config": {
"delay": 5000
},
"example": [5000, 5000, 5000]
}
}
}
def should_retry(error: IngestError, attempt: int) -> RetryDecision:
if error.code.startswith('E2'):
return RetryDecision(retry=False, reason="Non-retryable error")
config = RETRY_CONFIG.get(error.category)
if not config:
return RetryDecision(retry=False, reason="Unknown error category")
if attempt >= config.max_retries:
return RetryDecision(retry=False, reason="Max retries exceeded")
delay = calculate_backoff(config, attempt)
return RetryDecision(retry=True, delay=delay)
All error diagnostics must be deterministic and reproducible:
{
"diagnostics": {
"timestamp": "2025-12-04T12:00:00Z",
"traceId": "deterministic-trace-id",
"inputHash": "b3:...",
"stage": "normalization",
"context": {
"tool": "syft",
"toolVersion": "1.0.0",
"adapterVersion": "1.0.0",
"inputSize": 12345,
"componentCount": 42
},
"errorChain": [
{
"stage": "schema_validation",
"error": "Missing required field: artifacts[0].purl",
"path": "/artifacts/0"
}
]
}
}
For offline mode, diagnostics include:
- No timestamps that depend on wall clock
- Deterministic trace IDs (based on input hash)
- All context from bundled metadata
{
"diagnostics": {
"mode": "offline",
"kitVersion": "1.0.0",
"traceId": "b3:input-hash-derived-trace-id",
"kitHash": "b3:...",
"trustRootHash": "b3:..."
}
}
┌─────────────┐
│ Ingest │
│ Request │
└─────────────┘
│
▼
┌─────────────┐
│ Validate │──Error──► E2008 schema_invalid
└─────────────┘
│
▼
┌─────────────┐
│ Verify │──Error──► E2001-E2007 signature errors
│ Signature │
└─────────────┘
│
▼
┌─────────────┐
│ Normalize │──Error──► E2008-E2009 format errors
└─────────────┘
│
▼
┌─────────────┐
│ Store │──Error──► E1001-E1006 retryable errors
└─────────────┘
│
▼
┌─────────────┐
│ Success │
│ or Warn │
└─────────────┘
| Error Category | HTTP Status | Response Body |
|---|
| Retryable (E1xxx) | 503 | Error with Retry-After header |
| Rate limit (E1003) | 429 | Error with Retry-After header |
| Signature (E2001-E2007) | 400 | Error with details |
| Schema (E2008) | 400 | Error with validation details |
| Version (E2009) | 400 | Error with supported versions |
| No evidence (E2010) | 400 | Error with fallback options |
HTTP/1.1 400 Bad Request
Content-Type: application/json
X-Stellaops-Error-Code: E2001
X-StellaOps-TraceId: abc123...
{
"error": {
"code": "E2001",
"category": "signature_invalid",
"message": "DSSE signature verification failed",
"details": {...},
"retryable": false,
"diagnostics": {...}
}
}
HTTP/1.1 503 Service Unavailable
Content-Type: application/json
Retry-After: 5
X-Stellaops-Error-Code: E1004
X-Stellaops-Retry-Attempt: 1
{
"error": {
"code": "E1004",
"category": "service_unavailable",
"message": "Upstream service temporarily unavailable",
"retryable": true,
"retryAfter": 5000,
"attempt": 1,
"maxAttempts": 3
}
}
{
"level": "error",
"timestamp": "2025-12-04T12:00:00Z",
"logger": "stellaops.scanner.ingest",
"message": "Ingest failed: signature_invalid",
"error": {
"code": "E2001",
"category": "signature_invalid"
},
"context": {
"traceId": "abc123...",
"tool": "syft",
"inputHash": "b3:..."
}
}
- Sprint:
docs/implplan/SPRINT_0186_0001_0001_record_deterministic_execution.md (CM10) - Normalization:
docs/modules/scanner/design/competitor-ingest-normalization.md (CM1) - Verification:
docs/modules/scanner/design/competitor-signature-verification.md (CM2) - Offline Kit:
docs/modules/scanner/design/competitor-offline-ingest-kit.md (CM5)