Files
Triple-C/container/mission-control/docs/legs.md
Josh Knapp 2dffef0767
All checks were successful
Build App / compute-version (push) Successful in 2s
Build App / build-macos (push) Successful in 2m47s
Build Container / build-container (push) Successful in 9m0s
Build App / build-linux (push) Successful in 4m41s
Build App / build-windows (push) Successful in 5m33s
Build App / create-tag (push) Successful in 3s
Build App / sync-to-github (push) Successful in 10s
Bundle mission-control into Triple-C instead of cloning from GitHub
The mission-control (Flight Control) project is being closed upstream.
This embeds the project files directly in the repo under container/mission-control/,
bakes them into the Docker image at /opt/mission-control, and copies them into place
at container startup instead of git cloning from GitHub.

Also adds missing osc52-clipboard, audio-shim, and triple-c-sso-refresh to the
programmatic Docker build context in image.rs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 09:09:15 -07:00

384 lines
9.7 KiB
Markdown

# Legs
Legs are the AI-optimized layer of Flight Control. They provide structured, explicit instructions that AI agents can execute without ambiguity.
## What is a Leg?
A leg is a single, atomic unit of implementation work. Legs are:
- **Explicit**: No ambiguity about what "done" means
- **Bounded**: Clear start and end points
- **Context-complete**: All necessary information included
- **AI-consumable**: Structured for machine parsing
### Leg vs. Flight vs. Mission
| Aspect | Mission | Flight | Leg |
|--------|---------|--------|-----|
| Scope | Outcome | Feature | Task |
| Duration | Days-weeks | Hours-days | Minutes-hours |
| Modifications | Allowed | Allowed | Create new instead |
| Audience | Humans | Developers/AI | AI agents |
## Leg Structure
Legs follow a consistent structure optimized for AI consumption:
```markdown
# Leg: {slug}
## Flight Link
[Parent flight](../flight.md)
## Objective
Single sentence describing what this leg accomplishes.
## Context
Information the AI needs to understand this task.
## Inputs
- What exists before this leg runs
## Outputs
- What exists after this leg completes
## Acceptance Criteria
- [ ] Criterion 1
- [ ] Criterion 2
- [ ] Criterion 3
## Verification Steps
How to confirm each criterion is met (commands, manual checks, tools).
## Implementation Guidance
Specific patterns, approaches, or constraints.
## Files Likely Affected
- `path/to/file.ts`
- `path/to/test.ts`
```
## Writing Effective Legs
### Objectives
State exactly what the leg accomplishes in one sentence:
**Weak**:
> Set up the user stuff
**Strong**:
> Create the User model with email, password_hash, and timestamps fields
The objective should be:
- **Specific**: Clear what will be created/modified
- **Verifiable**: Can confirm completion by inspection
- **Atomic**: One cohesive piece of work
### Context
Provide information the AI needs but might not have:
```markdown
## Context
This project uses Prisma for database access. The existing `prisma/schema.prisma`
file contains the Post and Comment models. User will be referenced by these
models via foreign keys.
Authentication uses JWT tokens. The password_hash field will store bcrypt hashes
(cost factor 12). The email field must be unique and will be used as the login
identifier.
```
Good context includes:
- Relevant technology/framework information
- Relationship to existing code
- Design decisions from the parent flight
- Constraints that affect implementation
### Inputs and Outputs
Be explicit about state before and after:
```markdown
## Inputs
- Prisma schema at `prisma/schema.prisma` with Post and Comment models
- No existing User model or authentication
## Outputs
- User model added to Prisma schema
- Migration file generated
- Migration applied to development database
```
Inputs help the AI understand starting conditions. Outputs define the expected end state.
### Acceptance Criteria
Define exactly what "done" means:
```markdown
## Acceptance Criteria
- [ ] User model exists in `prisma/schema.prisma`
- [ ] User model has fields: id, email, password_hash, created_at, updated_at
- [ ] email field has `@unique` attribute
- [ ] Migration file exists in `prisma/migrations/`
- [ ] `npx prisma migrate status` shows no pending migrations
- [ ] TypeScript types generated (`npx prisma generate` succeeds)
```
Acceptance criteria should be:
- **Binary**: Either met or not met
- **Observable**: Can verify by inspection or test
- **Complete**: Nothing else required for "done"
### Verification Steps
Tell the AI exactly *how* to confirm each criterion:
```markdown
## Verification Steps
- Run `npx prisma migrate status` — should show no pending migrations
- Run `npm test` — all tests pass
- Open browser to `/users` — page loads without errors
- Tab through form fields — focus order matches visual order
- Run `npx lighthouse --accessibility` — score ≥ 90
```
Verification steps should be:
- **Executable**: Commands or specific actions
- **Deterministic**: Same result every time
- **Mapped to criteria**: Clear which criterion each step validates
For accessibility legs, include specific checks:
- Keyboard navigation sequences to test
- Screen reader commands (e.g., "navigate to main content via skip link")
- Automated tool commands (Lighthouse, axe-core)
### Implementation Guidance
Provide specific direction when needed:
```markdown
## Implementation Guidance
Use Prisma's native type for id:
```prisma
id String @id @default(cuid())
```
For timestamps, use Prisma's auto-managed fields:
```prisma
created_at DateTime @default(now())
updated_at DateTime @updatedAt
```
Do not add relations to Post/Comment yet—that's a separate leg.
```
Implementation guidance helps when:
- Project has specific patterns to follow
- There are multiple valid approaches (pick one)
- Constraints aren't obvious from context
### Files Likely Affected
Help the AI know where to look:
```markdown
## Files Likely Affected
- `prisma/schema.prisma` - Add User model
- `prisma/migrations/*` - New migration file (generated)
```
This isn't prescriptive—the AI might touch other files. It's a starting point for orientation.
## Leg Lifecycle
Legs progress through defined states:
### States
```
planning ──► ready ──► in-flight ──► landed ──► completed
└──► aborted
```
**planning**
Leg is being designed. Acceptance criteria and implementation guidance being defined.
**ready**
Leg design approved. Ready for implementation.
**in-flight**
AI agent actively working on implementation.
**landed**
Implementation complete. Flight log updated. Ready for review.
**completed**
Review passed. Acceptance criteria confirmed met.
**aborted**
Leg cancelled. Changes are rolled back. Document the reason in the flight log.
### State Transitions
| From | To | Trigger |
|------|----|---------|
| planning | ready | Design review passes |
| ready | in-flight | Developer begins work |
| in-flight | landed | Developer reports completion |
| in-flight | aborted | Cannot proceed, changes rolled back |
| landed | completed | Review passes |
| landed | in-flight | Issues found, needs fixes |
Note: Legs may only be modified while in `planning` state. Once `in-flight`, create new legs instead of modifying existing ones.
## Patterns for AI Consumption
### Be Explicit, Not Implicit
**Implicit** (requires inference):
> Add validation to the email field
**Explicit** (no inference needed):
> Add email validation: must be non-empty, valid email format (use validator library's isEmail), maximum 255 characters. Return 400 status with `{ error: "Invalid email format" }` on failure.
### Provide Examples
When patterns might be unclear, show don't tell:
```markdown
## Implementation Guidance
Follow the existing controller pattern:
```typescript
// Example from PostController
export async function createPost(req: Request, res: Response) {
const { title, content } = req.body;
if (!title) {
return res.status(400).json({ error: "Title is required" });
}
const post = await prisma.post.create({
data: { title, content, authorId: req.user.id }
});
return res.status(201).json(post);
}
```
Apply this pattern to the registration endpoint.
```
### State Constraints Clearly
Don't bury constraints in prose:
**Buried**:
> Create the endpoint and make sure it handles errors properly and validates input and also we're using Express and the response should be JSON.
**Clear**:
```markdown
## Constraints
- Framework: Express.js
- Response format: JSON
- Error handling: Return appropriate HTTP status codes
- Validation: Validate all input before processing
```
### Link to Flight for Context
When details would be redundant, reference the parent:
```markdown
## Context
See [parent flight](../flight.md) for:
- Authentication approach (JWT tokens)
- Session duration decisions
- Error response format standards
```
## Common Pitfalls
### Too Large
If a leg takes more than a few hours, it's probably too big. Signs:
- Multiple independent pieces of functionality
- Would benefit from intermediate checkpoints
- Hard to write clear acceptance criteria
Split into smaller legs.
### Too Small
If a leg is trivial, it adds overhead without value. Signs:
- Single line change
- No meaningful acceptance criteria
- Part of a larger atomic operation
Combine with related work.
### Ambiguous Acceptance Criteria
If criteria require judgment, they're not criteria:
**Ambiguous**: "Code is clean and readable"
**Specific**: "Functions are under 50 lines, no eslint warnings"
**Ambiguous**: "Error handling is good"
**Specific**: "All async operations wrapped in try/catch, errors logged with context"
### Missing Context
AI agents don't have your mental model. Include:
- Why this approach (from flight decisions)
- How this fits with existing code
- What patterns to follow
- What to avoid
## Relationship to Flight
Legs are generated from flights. The flight provides:
- Technical approach
- Design decisions
- Overall context
Legs provide:
- Specific implementation steps
- Explicit acceptance criteria
- Focused scope
A flight might generate many legs:
```
Flight: User Registration Flow
├── Leg: create-user-model
├── Leg: registration-endpoint
├── Leg: email-validation
├── Leg: password-hashing
├── Leg: registration-tests
└── Leg: registration-docs
```
## Immutability Principle
Once a leg is `in-flight`, don't modify it. If requirements change:
1. Mark the current leg as aborted (changes rolled back)
2. Create a new leg with updated requirements
3. Reference the old leg for context
This preserves history and prevents confusion about what the AI was asked to do.
## Next Steps
- [Workflow](workflow.md) — See the complete mission → flight → leg flow
- [Flights](flights.md) — Understand where legs come from