mirror of
https://github.com/cita-777/metapi.git
synced 2026-10-31 19:47:31 +08:00
* refactor: add harness engineering guardrails * fix: address harness review feedback --------- Co-authored-by: apple <apple@appledeMacBook-Pro.local>
141 lines
5.1 KiB
Markdown
141 lines
5.1 KiB
Markdown
# Metapi Harness Engineering
|
|
|
|
This document captures the repo-level engineering taste that should remain true
|
|
even when future work is performed by autonomous agents. The goal is not to
|
|
replace feature tests. The goal is to keep the repository readable,
|
|
review-friendly, and hard to drift.
|
|
|
|
## Why This Exists
|
|
|
|
`metapi` already has strong local discipline in several areas:
|
|
|
|
- architecture tests that pin important boundaries
|
|
- schema parity and runtime bootstrap verification across databases
|
|
- shared protocol helpers that deliberately replace parallel implementations
|
|
|
|
What was still missing was one place that states the mechanical rules behind
|
|
those choices and a lightweight loop that continuously checks for drift. This
|
|
document is that shared contract.
|
|
|
|
## Golden Principles
|
|
|
|
### 1. One Invariant, One Source Of Truth
|
|
|
|
If a helper, contract, or workflow already owns an invariant, new work should
|
|
reuse that home instead of creating a second implementation.
|
|
|
|
Examples:
|
|
|
|
- protocol shaping and normalization belong in `src/server/transformers/**`
|
|
- endpoint fallback belongs in `src/server/routes/proxy/endpointFlow.ts`
|
|
- proxy success/failure bookkeeping belongs in
|
|
`src/server/proxy-core/surfaces/sharedSurface.ts`
|
|
- schema heuristics belong in `src/server/db/schemaMetadata.ts`
|
|
|
|
### 2. Routes Are Adapters, Not Owners
|
|
|
|
`src/server/routes/**` should remain thin. Route files may register endpoints,
|
|
read Fastify request state, and delegate to shared orchestration. They should
|
|
not become the place where retry loops, protocol conversion, stream lifecycle,
|
|
or billing logic lives.
|
|
|
|
If a helper is imported outside a single route file, that helper should move to
|
|
`proxy-core`, `services`, `transformers`, or another neutral home.
|
|
|
|
### 3. Transformers Must Stay Protocol-Pure
|
|
|
|
Transformers are the protocol boundary. They may depend on canonical/shared
|
|
contracts, but they should not reach back into route files, Fastify handlers,
|
|
OAuth services, token routing, or runtime dispatch details.
|
|
|
|
In practice this means:
|
|
|
|
- `canonical` is the request truth source
|
|
- `shared/normalized` is the response truth source
|
|
- compatibility layers may orchestrate retries or fallback bodies, but they do
|
|
not redefine protocol semantics
|
|
|
|
### 4. Proxy-Core Follows The Golden Path
|
|
|
|
Proxy orchestration should prefer shared, tested paths instead of bespoke
|
|
surface-local logic.
|
|
|
|
Current preferred path:
|
|
|
|
- endpoint ranking and request shaping via `upstreamEndpoint.ts`
|
|
- endpoint-attempt loops via `executeEndpointFlow()`
|
|
- whole-body response decoding via `readRuntimeResponseText()`
|
|
- OAuth refresh, sticky/lease behavior, billing, and proxy logging via
|
|
`sharedSurface.ts`
|
|
- Codex header/session semantics via provider profiles and header utils
|
|
- Codex websocket transport via the dedicated websocket runtime, not generic
|
|
fetch executors
|
|
|
|
### 5. Platform Capability Must Be Explicit
|
|
|
|
Platform behavior is easy to let drift because it spans adapters, discovery,
|
|
endpoint preference, and routing. Any platform-specific behavior that matters
|
|
at runtime should be stated once and reused, not re-inferred in multiple
|
|
subsystems.
|
|
|
|
Thin adapters should stay honest. Feature-complete adapters should be tested as
|
|
feature-complete. Do not silently “upgrade” support through generic defaults.
|
|
|
|
### 6. Database Changes Must Stay Contract-Driven
|
|
|
|
Schema work already has one of the strongest harnesses in the repo. Keep it
|
|
that way.
|
|
|
|
- update Drizzle schema and SQLite migration history together
|
|
- regenerate checked-in contract/artifacts together
|
|
- keep cross-dialect bootstrap/upgrade generation contract-driven
|
|
- keep legacy startup compatibility narrow and spec-owned
|
|
|
|
### 7. Web Pages Are Orchestration Surfaces
|
|
|
|
Top-level pages should not be reused as shared component libraries.
|
|
|
|
- no page-to-page imports for reusable UI
|
|
- mobile behavior should reuse shared primitives first
|
|
- extract repeated modals, drawers, and panels into domain subfolders early
|
|
|
|
## First-Wave Drift Checks
|
|
|
|
The first repo-level drift loop is intentionally small and high-signal. It
|
|
checks for:
|
|
|
|
- transformer imports from `routes/proxy`
|
|
- new proxy-core surface body reads that bypass `readRuntimeResponseText()`
|
|
- new imports from `routes/proxy` inside `proxy-core` beyond the current debt
|
|
baseline
|
|
- new top-level page-to-page imports in the admin UI beyond the current debt
|
|
baseline
|
|
|
|
These checks live in `scripts/dev/repo-drift-check.ts` and are wired into CI.
|
|
|
|
## Tracked Debt Vs New Violations
|
|
|
|
The repository already contains some known architectural debt, especially where
|
|
`proxy-core` still imports helpers from `routes/proxy` and where one admin page
|
|
reuses another page's export.
|
|
|
|
The harness uses a ratchet:
|
|
|
|
- tracked debt is reported so it stays visible
|
|
- new violations fail CI
|
|
|
|
This keeps the repo moving forward without forcing a risky “rewrite
|
|
everything first” migration.
|
|
|
|
## Garbage Collection Loop
|
|
|
|
The harness loop is intentionally conservative:
|
|
|
|
1. rules are encoded in repo docs and executable checks
|
|
2. CI blocks new drift
|
|
3. a scheduled workflow generates a drift report artifact
|
|
4. targeted cleanup PRs can remove tracked debt in small slices
|
|
|
|
The goal is steady principal payments on technical debt, not occasional heroic
|
|
cleanup sprints.
|