docs(entry-points): contract + Pydantic schema (P1, BLOCKING GATE) #15
Reference in New Issue
Block a user
Delete Branch "feat/entry-points-contract"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Gemini review (delegated, attached below)
Verdict: PASS (after fixes)
Initial review returned FAIL with 6 issues. The follow-up commit
b443a93("fix(contract): address Gemini review blockers") addresses all 6:Coverage (PASS)
All 10 wiki endpoints and all 7 MCP tools have corresponding Pydantic models. Enum values mirror
schema.sqlexactly forWorkItemPhase,VerdictKind,IssueStatus, andGateKind.ErrorCodecorrectly omitsvalidation_error(422 stays FastAPI-default per wiki §95).Blockers — fixed in
b443a93Uuid36as a path-paramBaseModelwas dead-on-arrival — FastAPI cannot bind a raw path segment into a nested Pydantic model. Replaced withUUID36_PATTERN(regex constant) +is_uuid36()helper. P2 will useAnnotated[str, Path(pattern=UUID36_PATTERN)]. Wiki §124 and §135 reference the constant.ListEventsQuery.work_item_id: Optional[Uuid36]would not bind from a query string — Same root cause. Changed toOptional[str]with a docstring telling P2 to callis_uuid36()in the handler.recent_events: Field(max_length=20)was misleading dead code — Pydantic'smax_lengthonly constrainsstr. Removed; the 20-cap is the handler's job (documented in the model's docstring + wiki §137).Undocumented decisions — fixed in
b443a93MCP
ingest_storyomitsbudget_cycles— deliberate, but undocumented. Schema docstring now explains "operator decision, not agent"; wiki §5 has a paragraph called "MCP tools deliberately omit fields" with a grep pattern for P3 to verify nothing else slipped through.McpSystemStatusResponseasymmetry — only one MCP tool with a named response model. Docstring now explains the rationale (stable on-the-wire shape for the most user-facing tool).WorkItemResponse.last_feedback: Optional[Any]JSONB semantics — docstring now documents it as heterogeneous JSON (test output, conflict files, comments) and tells clients to render based onlast_verdict(which IS typed).Minor / non-blocking — accepted as documented
model_json_schema()(wiki §5 explicitly states this for all 7, not justlist_items).StatsResponse.phase_counts: dict[WorkItemPhase, int]works for OpenAPI; Postgres returns string keys — wiki §5 calls out that FastAPI needsmodel_dump(mode="json")or key coercion (P2 will trip on this once and recover).UUID36_PATTERNis now the single source of truth for the UUID regex —McpGetItemArgs.idandMcpAnswerQuestionArgs.issue_idboth reference it.Not issues (confirmed)
pass_alias onVerdictKindcorrectly serializes to"pass"— matches DB.since_idbeing best-effort is documented (wiki §148, schema docstring).Verification
python -W error -c "from damascus.api_schemas import *; print('ok')"→okUUID36_PATTERN,is_uuid36) — well above the 10 minimumpytest tests/contract/ tests/unit/ -q→28 passed in 3.15sagainst live Postgreswiki/entities/damascus-orchestrator.mdline 75What this PR is
P1 of the entry-points initiative. BLOCKING GATE for P2–P6. The contract that:
What this PR is NOT
cycle.py,state.py,cli.py,config.py,docker-compose.yml. That's P2.tests/contract/test_api_schemas_match_db.pyfor P2 to add.kaykayyali/damascus-wikirepo (per.gitignore:wiki/). Local edits towiki/concepts/entry-points-contract.mdandwiki/entities/damascus-orchestrator.mdare in this workspace but pushed separately to the damascus-wiki repo.Task tracking
t_609747efon boarddamascus-entry-pointsfeat/entry-points-contractb920f4e(initial),c505d6f(P1 polish v1),b443a93(Gemini review fixes)Heartbeat-authored. Cannot self-approve. Kay's call to merge.
Gemini flagged 6 issues on the entry-points contract. This commit addresses all of them. BLOCKERS fixed (P2 was blocked without these): 1. Uuid36 as a path-param BaseModel is dead code — FastAPI cannot bind a raw path segment into a nested Pydantic model. Replaced with UUID36_PATTERN (regex constant) + is_uuid36() helper. P2 imports the constant for Annotated[str, Path(pattern=...)]. 2. ListEventsQuery.work_item_id typed as Optional[Uuid36] (BaseModel) would not bind from a query string. Changed to Optional[str] with a docstring note that P2 must add is_uuid36() check in handler. 3. recent_events: Field(max_length=20) was misleading dead code — Pydantic's max_length only constrains str. Removed and moved the 20-event cap rationale to the docstring. UNDOCUMENTED DECISIONS now called out in docstrings: 4. McpIngestStoryArgs deliberately omits budget_cycles (operator decision, not agent). Docstring explains the rationale. 5. McpSystemStatusResponse asymmetry (only one MCP tool with a named response model) is now documented in the docstring. 6. WorkItemResponse JSONB fields (last_feedback, file_scope) now documented in the docstring. Also: McpGetItemArgs and McpAnswerQuestionArgs updated to use the new UUID36_PATTERN constant (single source of truth for the regex). Verification: - python -W error -c 'from damascus.api_schemas import *; print("ok")' prints 'ok' - 35 Pydantic models + 2 helpers (>= 10 required) - All four DB-mirroring enums match schema.sql exactly