- CLAUDE.md + README.md: new CTO Session Completion Protocol (authorized/done vocabulary, end-of-session summary requirement) - docs/engineering/08-workflow.md: Section 8 — CTO Session Completion Protocol - scripts/start-cto.sh: startup protocol updated to read PRD.md first - openspec/changes/process-governance-handoff-gap/: full OpenSpec change record (proposal, design, specs, tasks) - TBC/charter.md: Technical & Business Consultant charter - TBC/minutes/TBC-MIN-001-2026-04-07.md: inaugural TBC meeting minutes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
430 lines
14 KiB
Markdown
430 lines
14 KiB
Markdown
# 08 — Engineering Workflow
|
|
|
|
---
|
|
|
|
## 9.1 OpenSpec Spec-First Workflow
|
|
|
|
Every feature in this codebase was designed before it was implemented.
|
|
The OpenSpec workflow enforces this order without exception.
|
|
|
|
### The Full Sequence
|
|
|
|
```
|
|
1. CEO identifies a feature or change
|
|
└── Documents it in the backlog
|
|
|
|
2. CEO approves the feature for the current sprint
|
|
└── Creates an OpenSpec change document
|
|
|
|
3. Virtual Architect designs the API
|
|
└── Writes the OpenAPI 3.0 spec BEFORE any implementation
|
|
└── Produces spec file in docs/openapi/ or openspec/changes/<name>/specs/
|
|
└── Every endpoint in the spec must have:
|
|
- Summary and description
|
|
- Request body schema (with all validation rules)
|
|
- All response schemas (every status code)
|
|
- Error response schemas
|
|
- Authentication requirements
|
|
- Example requests and responses
|
|
|
|
4. Virtual CTO reviews the spec
|
|
└── Checks DRY, SOLID, AGNTCY compliance, completeness
|
|
└── Either approves or returns with corrections
|
|
|
|
5. CEO approves the spec
|
|
└── Only after CTO approval
|
|
└── Scope changes require re-running from step 1
|
|
|
|
6. Virtual Principal Developer implements the spec
|
|
└── Implementation must match the spec exactly
|
|
└── TypeScript strict mode, DRY, SOLID, JSDoc on all public methods
|
|
└── Zero any types
|
|
└── All errors typed and handled
|
|
|
|
7. Virtual QA Engineer writes and runs tests
|
|
└── Unit tests: >80% coverage on all services
|
|
└── Integration tests: every endpoint in the spec tested
|
|
└── Edge cases: null, empty, invalid inputs
|
|
└── Performance: token endpoints <100ms, all others <200ms
|
|
└── Verifies spec matches implementation exactly
|
|
|
|
8. Virtual CTO reviews the implementation and QA report
|
|
└── If quality gates not met: returns to step 6 or 7
|
|
└── If approved: notifies CEO
|
|
|
|
9. CEO approves → code is merged to develop
|
|
└── No code ever goes to main without CEO awareness
|
|
```
|
|
|
|
### Rule: No Code Without a Spec
|
|
|
|
If you find yourself implementing something without an approved OpenAPI spec,
|
|
stop. Write the spec first, get it reviewed, then implement. This is not
|
|
bureaucracy — it is how you avoid building the wrong thing.
|
|
|
|
---
|
|
|
|
## 9.2 OpenSpec CLI Commands Reference
|
|
|
|
OpenSpec is the change management workflow built into this project. Changes
|
|
are tracked in `openspec/changes/`.
|
|
|
|
```bash
|
|
# Create a new change (starts the design process)
|
|
openspec new change <name>
|
|
# Creates: openspec/changes/<name>/proposal.md, design.md, specs/, tasks.md
|
|
|
|
# Check the status of all active changes
|
|
openspec status
|
|
# Shows: change name, phase (design/implementation/review), completion %
|
|
|
|
# List all active changes
|
|
openspec list
|
|
|
|
# Get implementation instructions for a change
|
|
openspec instructions <name>
|
|
# Outputs the tasks.md formatted for implementation
|
|
|
|
# Archive a completed change
|
|
openspec archive <name>
|
|
# Moves: openspec/changes/<name>/ → openspec/archive/<name>/
|
|
```
|
|
|
|
### Change Lifecycle
|
|
|
|
```
|
|
openspec/changes/<name>/
|
|
├── proposal.md — Business case and feature description (CEO-authored)
|
|
├── design.md — Technical design decisions (Architect-authored)
|
|
├── specs/ — OpenAPI specs and interface contracts
|
|
│ └── *.md or *.yaml
|
|
└── tasks.md — Implementation tasks checklist (checked off as work completes)
|
|
```
|
|
|
|
---
|
|
|
|
## 9.3 Branching Strategy
|
|
|
|
### Branch naming
|
|
|
|
```
|
|
feature/<short-description> — New features (from develop)
|
|
fix/<short-description> — Bug fixes (from develop)
|
|
docs/<short-description> — Documentation changes only (from develop)
|
|
```
|
|
|
|
### Workflow
|
|
|
|
```
|
|
main — Production. Only CTO-approved, CEO-aware merges.
|
|
└── develop — Integration branch. All feature branches merge here.
|
|
└── feature/my-feature — Your work branch
|
|
```
|
|
|
|
1. Create your branch from `develop`:
|
|
```bash
|
|
git checkout develop
|
|
git pull origin develop
|
|
git checkout -b feature/my-feature
|
|
```
|
|
|
|
2. Work on your branch, committing as you go.
|
|
|
|
3. When ready, push and open a PR targeting `develop`:
|
|
```bash
|
|
git push -u origin feature/my-feature
|
|
gh pr create --base develop --title "feat: my feature" --body "..."
|
|
```
|
|
|
|
4. Virtual QA reviews the PR (all quality gates must pass).
|
|
|
|
5. Virtual CTO approves the PR.
|
|
|
|
6. Merge to `develop`.
|
|
|
|
7. `develop` → `main` requires an explicit CEO decision.
|
|
|
|
**Rule:** Never push directly to `main` or `develop`. Always work through a PR.
|
|
|
|
---
|
|
|
|
## 9.4 TypeScript and Code Standards
|
|
|
|
### Strict Mode
|
|
|
|
All compiler strictness flags are enabled in `tsconfig.json`. These are
|
|
non-negotiable:
|
|
|
|
```json
|
|
{
|
|
"strict": true,
|
|
"noImplicitAny": true,
|
|
"strictNullChecks": true,
|
|
"noUnusedLocals": true,
|
|
"noUnusedParameters": true,
|
|
"noImplicitReturns": true
|
|
}
|
|
```
|
|
|
|
**Consequence of violation:** The TypeScript compiler (`npm run build`) will fail.
|
|
PRs that cause build failures are rejected automatically.
|
|
|
|
### No `any` Types
|
|
|
|
Never use `any`. If a third-party library returns `unknown` or `any`, cast it to
|
|
a specific interface you define:
|
|
|
|
```typescript
|
|
// BAD
|
|
const result: any = await vault.read(path);
|
|
const secret = result.data.data.clientSecret;
|
|
|
|
// GOOD
|
|
interface KvV2ReadResponse {
|
|
data: { data: Record<string, string>; metadata: { version: number; } };
|
|
}
|
|
const result = (await vault.read(path)) as KvV2ReadResponse;
|
|
const secret = result.data.data.clientSecret;
|
|
```
|
|
|
|
### DRY (Don't Repeat Yourself)
|
|
|
|
Zero code duplication. See `04-codebase-structure.md` section 5.5 for the complete
|
|
mapping of what lives where. Before writing a utility function, check whether
|
|
it already exists in `src/utils/`.
|
|
|
|
### SOLID Principles
|
|
|
|
Each service has a single, clear responsibility. If you find yourself adding a
|
|
method to `AgentService` that queries the `audit_events` table, stop — that
|
|
belongs in `AuditService`. If you find yourself adding SQL to a controller, stop —
|
|
that belongs in a repository.
|
|
|
|
### JSDoc on All Public Methods
|
|
|
|
Every public class, method, and interface must have a JSDoc comment that includes:
|
|
- `@param` for every parameter
|
|
- `@returns` describing the return value
|
|
- `@throws` for every error that can be thrown
|
|
|
|
```typescript
|
|
/**
|
|
* Registers a new AI agent identity.
|
|
*
|
|
* @param data - Agent registration request data.
|
|
* @param ipAddress - Client IP for audit logging.
|
|
* @param userAgent - Client User-Agent for audit logging.
|
|
* @returns The newly created agent record.
|
|
* @throws FreeTierLimitError if the 100-agent limit is reached.
|
|
* @throws AgentAlreadyExistsError if the email is already registered.
|
|
*/
|
|
async registerAgent(data: ICreateAgentRequest, ipAddress: string, userAgent: string): Promise<IAgent>
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
Always throw a typed error from the `SentryAgentError` hierarchy. Never throw
|
|
raw `Error` objects with string messages in service or controller code:
|
|
|
|
```typescript
|
|
// BAD
|
|
throw new Error('Agent not found');
|
|
|
|
// GOOD
|
|
throw new AgentNotFoundError(agentId);
|
|
```
|
|
|
|
The `errorHandler` middleware maps `SentryAgentError` subclasses to HTTP status
|
|
codes automatically. Adding a new error type only requires adding a class in
|
|
`src/utils/errors.ts`.
|
|
|
|
---
|
|
|
|
## 9.5 PR Checklist
|
|
|
|
Every pull request must pass all items before it can be merged.
|
|
|
|
```
|
|
Code quality:
|
|
- [ ] TypeScript builds without errors: npm run build
|
|
- [ ] No any types introduced
|
|
- [ ] All new public methods have JSDoc
|
|
- [ ] ESLint passes: npm run lint
|
|
- [ ] No code duplication — logic extracted to utils/services
|
|
|
|
Testing:
|
|
- [ ] Unit tests added for all new service methods
|
|
- [ ] Integration tests added for all new API endpoints
|
|
- [ ] Coverage threshold maintained: npm run test:unit -- --coverage
|
|
(>80% statements, branches, functions, lines)
|
|
- [ ] Integration tests pass against real PostgreSQL and Redis
|
|
|
|
Spec compliance:
|
|
- [ ] Implementation matches the approved OpenAPI spec exactly
|
|
- [ ] If the spec needs updating, the spec was updated BEFORE the code was changed
|
|
|
|
Documentation:
|
|
- [ ] docs/engineering/ updated if the change affects service interfaces or workflows
|
|
- [ ] CHANGELOG.md updated with a summary of the change
|
|
- [ ] Any new environment variables documented in docs/engineering/07-dev-setup.md
|
|
|
|
Database:
|
|
- [ ] If a new table or column is added, a migration file exists in src/db/migrations/
|
|
- [ ] Migration file is numbered correctly and tested locally
|
|
|
|
Review:
|
|
- [ ] Virtual CTO reviewed the implementation
|
|
- [ ] Virtual QA signed off on tests
|
|
```
|
|
|
|
---
|
|
|
|
## 9.6 Virtual Engineering Team Roles for Contributors
|
|
|
|
External contributors operate within the same team structure as the internal
|
|
Virtual Engineering Team. Here is how to interact with each role:
|
|
|
|
**Virtual CTO (architecture gate)**
|
|
Opens architectural discussions by filing a GitHub issue labeled `architecture`.
|
|
The Virtual CTO must approve any change to:
|
|
- The layered architecture (adding a direct DB call in a controller)
|
|
- The error hierarchy
|
|
- The authentication or authorisation flow
|
|
- Any new dependency (package)
|
|
- Multi-region deployment topology
|
|
|
|
**Virtual Architect (spec owner)**
|
|
All API changes require an updated OpenAPI spec. If you are adding an endpoint,
|
|
file an issue labeled `spec-change` with your proposed additions before writing
|
|
any code. The Architect will review and approve the spec.
|
|
|
|
**Virtual Principal Developer (code reviewer)**
|
|
All implementation PRs are reviewed for TypeScript compliance, DRY violations,
|
|
SOLID violations, JSDoc completeness, and correctness against the spec.
|
|
|
|
**Virtual QA Engineer (quality gate)**
|
|
All PRs require >80% coverage and passing integration tests. The QA Engineer
|
|
will review test completeness and flag edge cases that need coverage.
|
|
|
|
---
|
|
|
|
## 9.7 Commit Message Conventions
|
|
|
|
This project uses **Conventional Commits** (https://www.conventionalcommits.org).
|
|
|
|
### Format
|
|
|
|
```
|
|
<type>(<optional scope>): <short description>
|
|
|
|
<optional body — why this change was made>
|
|
|
|
<optional footer — breaking changes, issue references>
|
|
```
|
|
|
|
### Types
|
|
|
|
| Type | When to use | Example |
|
|
|------|-------------|---------|
|
|
| `feat` | A new feature | `feat(agents): add agent status filter to list endpoint` |
|
|
| `fix` | A bug fix | `fix(auth): handle TokenExpiredError separately from JsonWebTokenError` |
|
|
| `docs` | Documentation only | `docs(engineering): add credential rotation walkthrough` |
|
|
| `test` | Adding or updating tests | `test(oauth2): add monthly token limit integration test` |
|
|
| `chore` | Build, tooling, dependencies | `chore: update jest to 29.7.0` |
|
|
| `refactor` | Code change with no behaviour change | `refactor(credential): extract secret storage to VaultClient` |
|
|
| `perf` | Performance improvement | `perf(token): make audit log write fire-and-forget` |
|
|
|
|
### Rules
|
|
|
|
- Keep the description under 72 characters
|
|
- Use the imperative mood: "add" not "added" or "adds"
|
|
- Include the scope in parentheses when the change is limited to one area
|
|
- Reference issues in the footer: `Closes #123`
|
|
|
|
### Examples
|
|
|
|
```
|
|
feat(vault): add optional HashiCorp Vault credential backend
|
|
|
|
Adds VaultClient wrapping node-vault for KV v2 operations.
|
|
When VAULT_ADDR and VAULT_TOKEN are set, new credentials are
|
|
stored in Vault instead of as bcrypt hashes in PostgreSQL.
|
|
|
|
Backwards compatible: existing bcrypt credentials continue to work.
|
|
|
|
Closes #45
|
|
```
|
|
|
|
```
|
|
fix(opa): normalise /token/revoke path before OPA lookup
|
|
|
|
The path /api/v1/token/revoke was not in the normalisation
|
|
switch, causing OPA to deny all revocation requests even with
|
|
the correct scope.
|
|
```
|
|
|
|
```
|
|
docs: add engineering knowledge base for new hires
|
|
|
|
Adds docs/engineering/ with 11 documents covering architecture,
|
|
service deep-dives, code walkthroughs, dev setup, workflow,
|
|
testing, deployment, and SDK guide.
|
|
```
|
|
|
|
---
|
|
|
|
## 8. CTO Session Completion Protocol
|
|
|
|
This section applies to the Virtual CTO role. It defines the required communication protocol at the end of any session that involves CEO-authorized actions.
|
|
|
|
### 8.1 Completion Confirmation (Required)
|
|
|
|
After the CEO authorizes any action via `#vpe-cto-approvals`, the CTO MUST:
|
|
|
|
1. Execute the authorized action
|
|
2. Post a **completion confirmation** to `#vpe-cto-approvals` before closing the session
|
|
|
|
The confirmation message MUST include:
|
|
|
|
| Field | Description |
|
|
|-------|-------------|
|
|
| Action completed | What was done |
|
|
| Outcome | Success or failure |
|
|
| Commit hash | Required if the action involved a git commit |
|
|
| Resulting state | What state the system/repo is in now |
|
|
|
|
> Authorization and completion are two distinct, required messages. An authorization alone does not constitute completion.
|
|
|
|
### 8.2 End-of-Session Summary (Required)
|
|
|
|
Before closing any session that contains completed, pending, or in-progress work, the CTO MUST post a structured summary to `#vpe-cto-approvals`:
|
|
|
|
```
|
|
## End-of-Session Summary
|
|
|
|
### Completed This Session
|
|
- <action> — <commit hash or outcome>
|
|
|
|
### Pending (Authorized but Not Yet Executed)
|
|
- <action> — authorized in msg #<id>, not yet executed
|
|
|
|
### Requires CEO Action Next Session
|
|
- <decision or approval needed>
|
|
```
|
|
|
|
If nothing is pending and all actions are complete, a brief "session complete, nothing pending" message is sufficient.
|
|
|
|
### 8.3 Authorized vs. Done Vocabulary
|
|
|
|
These two terms have precise, non-interchangeable meanings:
|
|
|
|
| Term | Meaning |
|
|
|------|---------|
|
|
| **Authorized** | CEO has granted permission. Action has NOT been executed. |
|
|
| **Committed / Completed / Deployed** | Action has been executed and confirmed with evidence. |
|
|
|
|
Rules:
|
|
- Never use "completed" or "committed" to describe an action that has only been approved
|
|
- Always include supporting evidence when claiming completion (e.g., commit hash, test output)
|
|
- If no commit hash exists for a git action, the action is not done — regardless of authorization status
|