4.9 KiB
4.9 KiB
Cross-Layer Thinking Guide
Purpose: prevent contract drift across
docs/protocols-> backend -> frontend.
Practical Conventions
- Treat
docs/protocols/**as the contract source of truth before code changes. - For any API/event/error contract change, verify all three sides in one pass:
- Protocol doc
- Backend transport/output
- Frontend parsing/mapping
- Prefer explicit boundary checks over implicit assumptions (status/code/date/run lifecycle).
- When touching cross-layer behavior, keep a short written checkpoint list in task notes (aligned with
.opencode/commands/trellis/finish-work.mdcross-layer verification items).
Project-Specific Boundary Map
| Boundary | Contract Source | Backend Evidence | Frontend Evidence |
|---|---|---|---|
| HTTP errors | docs/protocols/common/http-error-codes.md |
backend/src/core/http/response.py, backend/src/app.py |
apps/lib/data/network/api_exception.dart, apps/lib/data/network/error_code_mapper.dart |
| Todo model | docs/protocols/models/todo.md |
backend/src/v1/todo/schemas.py, backend/src/v1/todo/router.py |
apps/lib/features/todo/data/apis/todo_api.dart |
| Agent SSE events | docs/protocols/agent/sse-events.md |
backend/src/v1/agent/router.py |
apps/lib/features/chat/data/apis/chat_api_impl.dart, apps/lib/core/chat/ag_ui_service.dart |
Real File Path Examples
docs/protocols/common/http-error-codes.mdbackend/src/v1/agent/router.pyapps/lib/core/chat/ag_ui_service.dart
Contract Checkpoints (Required for cross-layer work)
1) Endpoint and payload shape
- Confirm method/path/query/body on both sides.
- Example pair:
- Backend:
backend/src/v1/todo/router.py(/api/v1/todos, querystatus/priority) - Frontend:
apps/lib/features/todo/data/apis/todo_api.dart(getTodos,createTodo,reorderTodos)
- Backend:
2) Error code transport and mapping
- Backend should return RFC7807 + stable
code/params. - Frontend should localize by
code, not by free-textdetail. - Example triplet:
docs/protocols/common/http-error-codes.mdbackend/src/core/http/response.pyapps/lib/data/network/error_code_mapper.dart
3) Event lifecycle completeness (SSE)
- Ensure lifecycle expectations are symmetric:
- backend stream semantics (filter + terminal event)
- frontend stream completion/recovery logic
- Example pair:
backend/src/v1/agent/router.py(target run filtering, terminal events)apps/lib/core/chat/ag_ui_service.dart(terminal event required for stream completion)
4) Date/time and ID boundary parsing
- Check datetime serialization/parsing and UUID/string assumptions across layers.
- Example:
backend/src/v1/todo/schemas.py(datetime,UUID)apps/lib/features/todo/data/apis/todo_api.dart(DateTime.parse, string IDs)
Project Examples
Example A: Todo contract alignment
- Protocol defines field names and ordering rules:
docs/protocols/models/todo.md - Backend enforces schema and route behavior:
backend/src/v1/todo/schemas.py,backend/src/v1/todo/router.py - Frontend maps to model parsing and request payloads:
apps/lib/features/todo/data/apis/todo_api.dart
Checklist:
- field names (
schedule_item_ids,created_at,updated_at) match - enums/ranges (
status,priority) match - reorder payload shape (
items: [{id, priority, order}]) matches
Example B: Agent SSE run lifecycle alignment
- Protocol lifecycle doc:
docs/protocols/agent/sse-events.md - Backend stream filtering/termination:
backend/src/v1/agent/router.py - Frontend consumption/recovery:
apps/lib/core/chat/ag_ui_service.dart
Checklist:
- frontend sends
runIdquery for/events - backend only emits target run to subscriber
- frontend treats
RUN_FINISHED/RUN_ERRORas terminal for stream completion
Anti-patterns (with current evidence)
- Changing backend error codes without updating protocol registry and frontend mapper.
- Synchronization points:
http-error-codes.md+error_code_mapper.dart.
- Synchronization points:
- Inferring user-facing behavior from
detailfree text.- Frontend already supports code-first mapping in
api_exception.dart; bypassing this creates localization drift.
- Frontend already supports code-first mapping in
- Swallowing boundary failures in stream/auth paths.
- Existing weak branches (do not extend):
apps/lib/app/di/injection.dartrefresh callback catch returnsfalseapps/lib/core/chat/ag_ui_service.dartmalformed SSE payload parse catch ignores payloadbackend/src/v1/agent/router.pySSE slot acquire/release failure falls back to warning + continue
- Existing weak branches (do not extend):
Uncertainties / Gaps
- No repository-wide automated checker currently validates full cross-layer parity (protocol doc <-> backend implementation <-> frontend mapping/event consumer).
- Some fallback branches exist for runtime resilience in legacy paths; whether to hard-fail vs degrade is not yet uniformly specified across all modules.