# 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//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 # Creates: openspec/changes//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 # Outputs the tasks.md formatted for implementation # Archive a completed change openspec archive # Moves: openspec/changes// → openspec/archive// ``` ### Change Lifecycle ``` openspec/changes// ├── 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/ — New features (from develop) fix/ — Bug fixes (from develop) docs/ — 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; 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 ``` ### 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 ``` (): ``` ### 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 - ### Pending (Authorized but Not Yet Executed) - — authorized in msg #, not yet executed ### Requires CEO Action Next Session - ``` 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