# Improved Internal Protocol Design

## Current Issues with TAP Protocol

1. **Delimiter Conflict**: Using `#` for metadata conflicts with test descriptions containing `#`
2. **Ambiguous Parsing**: No clear boundary between test name and metadata
3. **Limited Extensibility**: Adding new metadata requires regex changes
4. **Mixed Concerns**: Protocol data mixed with human-readable output

## Proposed Internal Protocol v2

### Design Principles

1. **Clear Separation**: Protocol data must be unambiguously separated from user content
2. **Extensibility**: Easy to add new metadata without breaking parsers
3. **Backwards Compatible**: Can coexist with standard TAP for gradual migration
4. **Machine Readable**: Structured format for reliable parsing
5. **Human Friendly**: Still readable in raw form

### Protocol Options

#### Option 1: Special Delimiters
```
ok 1 - test description ::TSTEST:: {"time":123,"retry":0}
not ok 2 - another test ::TSTEST:: {"time":45,"error":"timeout"}
ok 3 - skipped test ::TSTEST:: {"time":0,"skip":"not ready"}
```

**Pros**: 
- Simple to implement
- Backwards compatible with TAP parsers (they ignore the suffix)
- Easy to parse with split()

**Cons**: 
- Still could conflict if test name contains `::TSTEST::`
- Not standard TAP

#### Option 2: Separate Metadata Lines
```
ok 1 - test description
::METADATA:: {"test":1,"time":123,"retry":0}
not ok 2 - another test  
::METADATA:: {"test":2,"time":45,"error":"timeout"}
```

**Pros**:
- Complete separation of concerns
- No chance of conflicts
- Can include arbitrary metadata

**Cons**:
- Requires correlation between lines
- More complex parsing

#### Option 3: YAML Blocks (TAP 13 Compatible)
```
ok 1 - test description
  ---
  time: 123
  retry: 0
  ...
not ok 2 - another test
  ---
  time: 45
  error: timeout
  stack: |
    Error: timeout
      at Test.run (test.js:10:5)
  ...
```

**Pros**:
- Standard TAP 13 feature
- Structured data format
- Human readable
- Extensible

**Cons**:
- More verbose
- YAML parsing overhead

#### Option 4: Binary Protocol Markers (Recommended)
```
ok 1 - test description
␛[TSTEST:eyJ0aW1lIjoxMjMsInJldHJ5IjowfQ==]␛
not ok 2 - another test
␛[TSTEST:eyJ0aW1lIjo0NSwiZXJyb3IiOiJ0aW1lb3V0In0=]␛
```

Using ASCII escape character (␛ = \x1B) with base64 encoded JSON.

**Pros**:
- Zero chance of accidental conflicts
- Compact
- Fast to parse
- Invisible in most terminals

**Cons**:
- Not human readable in raw form
- Requires base64 encoding/decoding

### Recommended Implementation: Hybrid Approach

Use multiple strategies based on context:

1. **For timing and basic metadata**: Use structured delimiters
   ```
   ok 1 - test name ⟦time:123,retry:0⟧
   ```

2. **For complex data (errors, snapshots)**: Use separate protocol lines
   ```
   ok 1 - test failed
   ⟦TSTEST:ERROR⟧
   {"message":"Assertion failed","stack":"...","diff":"..."}
   ⟦/TSTEST:ERROR⟧
   ```

3. **For human-readable output**: Keep standard TAP comments
   ```
   # Test suite: User Authentication
   ok 1 - should login
   ```

### Implementation Plan

#### Phase 1: Parser Enhancement
1. Add new protocol parser alongside existing TAP parser
2. Support both old and new formats during transition
3. Add protocol version negotiation

#### Phase 2: Metadata Structure
```typescript
interface TestMetadata {
  // Timing
  time: number;           // milliseconds
  startTime?: number;     // Unix timestamp
  endTime?: number;       // Unix timestamp
  
  // Status
  skip?: string;          // skip reason
  todo?: string;          // todo reason
  retry?: number;         // retry attempt
  maxRetries?: number;    // max retries allowed
  
  // Error details
  error?: {
    message: string;
    stack?: string;
    diff?: string;
    actual?: any;
    expected?: any;
  };
  
  // Test context
  file?: string;          // source file
  line?: number;          // line number
  column?: number;        // column number
  
  // Custom data
  tags?: string[];        // test tags
  custom?: Record<string, any>;
}
```

#### Phase 3: Protocol Messages

##### Success Message
```
ok 1 - user authentication works
⟦TSTEST:META:{"time":123,"tags":["auth","unit"]}⟧
```

##### Failure Message
```
not ok 2 - login fails with invalid password
⟦TSTEST:META:{"time":45,"retry":1,"maxRetries":3}⟧
⟦TSTEST:ERROR⟧
{
  "message": "Expected 401 but got 500",
  "stack": "Error: Expected 401 but got 500\n    at Test.run (auth.test.ts:25:10)",
  "actual": 500,
  "expected": 401
}
⟦/TSTEST:ERROR⟧
```

##### Skip Message
```
ok 3 - database integration test ⟦TSTEST:SKIP:No database connection⟧
```

##### Snapshot Communication
```
⟦TSTEST:SNAPSHOT:user-profile⟧
{
  "name": "John Doe",
  "email": "john@example.com",
  "roles": ["user", "admin"]
}
⟦/TSTEST:SNAPSHOT⟧
```

### Migration Strategy

1. **Version Detection**: First line indicates protocol version
   ```
   ⟦TSTEST:PROTOCOL:2.0⟧
   TAP version 13
   ```

2. **Gradual Rollout**:
   - v1.10: Add protocol v2 parser, keep v1 generator
   - v1.11: Generate v2 by default, v1 with --legacy flag  
   - v2.0: Remove v1 support

3. **Feature Flags**:
   ```typescript
   tap.settings({
     protocol: 'v2',        // or 'v1', 'auto'
     protocolFeatures: {
       structuredErrors: true,
       enhancedTiming: true,
       binaryMarkers: false
     }
   });
   ```

### Benefits of New Protocol

1. **Reliability**: No more regex fragility or description conflicts
2. **Performance**: Faster parsing with clear boundaries
3. **Extensibility**: Easy to add new metadata fields
4. **Debugging**: Rich error information with stack traces and diffs
5. **Integration**: Better IDE and CI/CD tool integration
6. **Forward Compatible**: Room for future enhancements

### Example Parser Implementation

```typescript
class ProtocolV2Parser {
  private readonly MARKER_START = '⟦TSTEST:';
  private readonly MARKER_END = '⟧';
  
  parseMetadata(line: string): TestMetadata | null {
    const start = line.lastIndexOf(this.MARKER_START);
    if (start === -1) return null;
    
    const end = line.indexOf(this.MARKER_END, start);
    if (end === -1) return null;
    
    const content = line.substring(start + this.MARKER_START.length, end);
    const [type, data] = content.split(':', 2);
    
    switch (type) {
      case 'META':
        return JSON.parse(data);
      case 'SKIP':
        return { skip: data };
      case 'TODO':
        return { todo: data };
      default:
        return null;
    }
  }
  
  parseTestLine(line: string): ParsedTest {
    // First extract any metadata
    const metadata = this.parseMetadata(line);
    
    // Then parse the TAP part (without metadata)
    const cleanLine = this.removeMetadata(line);
    const tapResult = this.parseTAP(cleanLine);
    
    return { ...tapResult, metadata };
  }
}
```

### Next Steps

1. Implement proof of concept with basic metadata support
2. Test with real-world test suites for edge cases
3. Benchmark parsing performance
4. Get feedback from users
5. Finalize protocol specification
6. Implement in both tapbundle and tstest