feat(api): /api/v1 projects, states, labels and work items with the oracle gate on those operations
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 5/5
- Thời gian dự kiến
- Hơn một tuần
- Mức phù hợp với người mới
- 20/100
Hướng nghiên cứu
Start with crates/thrust-api/src/lib.rs, the migration at crates/thrust-adapters-postgres/migrations/0001_init.sql, and the pinned oracle schema and harness described in the issue. Read the referenced ADRs and resolve the dependencies on #35, #36, and #47 before taking this on. Run scripts/oracle-v1.sh against native-pg and worker-cf; done means both and the Plane control pass with zero unaccepted or stale exceptions, corpus comparisons match, and the 32-operation schema diff has no breaking changes.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Context
No wire-compatible route exists. thrust_api::router() (crates/thrust-api/src/lib.rs:269-293) puts only the slice's non-Plane routes under /api/v1 (:278-291), and #47 moves them out. Requests authenticate with Authorization: Bearer through the SessionStore (:82-99), not with X-Api-Key. Errors use a Thrust shape, {"error":{"code","message"}} (:47-49), and every authentication failure is a 401 (:54). The schema has projects (id, workspace_id, name) and a work_items table with no state, priority, labels, assignees, parent or dates (crates/thrust-adapters-postgres/migrations/0001_init.sql:4-8,26-41), and no states or labels table. Spike 0008 (bead plane-b6a) built the v1 oracle as the schema, an exception register and a golden corpus (research/0005; ADR-0122 round 26). The oracle exists only on a local, unpushed branch of the Plane fork, feat/plane-b6a-upstream-sync-oracle (research/0005:4-5; Q-0122.4, QUESTIONS.md:293), and it has only ever run against Plane.
Problem
- M1 includes
/api/v1for projects, states, labels and work items, with the oracle gate on those operations (review §3, FR-01). ADR-0031 keeps v1 wire-compatible and confirms it with the oracle (lines 23, 39). ADR-0032 requires a CI breaking-change diff of the code-first schema (line 41). That diff is not done yet because it "needs the Rust v1 slice" (line 70). - In the pinned schema (
oracle/schema/openapi.v1.json, 130 operations), these resources are the tagsProjects(8),States(5),Labels(5) andWork Items(14): 32 operations, including both theissues/andwork-items/families, search and lookup by identifier. The fuzzer skips seven of them (the six DELETEs and archive, under SX-001 and SX-002,oracle/exceptions.yaml:25-44). The corpus covers six of those seven; it has no exchange forDELETE .../issues/{pk}/. - The gate cannot be pointed at a partial implementation as it stands.
run_conformance.pyruns the whole schema (:56-80), a register entry that matches nothing fails as stale, and the vacuity floors are sized for the full surface (:205-212;exceptions.yaml:22-23: 100 operations tested, 40 with a 2xx). Only seven of the 12 entries touch the 32 operations (EX-001 to EX-004, EX-006, EX-007, EX-011), so the other five would go stale. Staleness is also counted per entry, so reproducing a quirk on one of an entry's operations hides its absence on the others. - The owner chose to reproduce these quirks (ADR-0031 lines 64-74; ADR-0033 lines 79, 83). Only a missing key gets 401; an invalid, expired or inactive key gets 403
{"detail":"Given API token is not valid"}(Planeapps/api/plane/api/middleware/api_authentication.py:32-38). Error bodies come in two shapes. State create returns 200. Aper_pageof 0 or −1, and some work-item create payloads, give 500 (EX-001, EX-002). ADR-0052 still says "revoke key → 401" (line 53). - Every in-scope corpus exchange that passes authentication and permissions carries
x-ratelimit-remainingandx-ratelimit-reset; the 401 and 403 answers carry neither (oracle/NORMALISATION.md:23; Planeapps/api/plane/api/rate_limit.py:47-48, default60/minuteatsettings/common.py:154). The port can reportremaining(crates/thrust-ports/src/lib.rs:208-211). The Workers Rate Limiting binding (ADR-0033, round-29 note) reports only whether a request is allowed.
Proposal
- Routes: serve the 32 operations under
/api/v1/workspaces/{slug}/as a thin surface overthrust-coreuse-cases (ADR-0031 line 60). The project and work-item use-cases are shared with #44; the state and label use-cases are new. Each one runs on a&Scopefromauthorize(#35), with the workspace resolved from{slug}through membership (#36). - Schema and types: add
workspaces(withslug),workspace_members,api_tokens,statesandlabels, plus the work-item columns and join tables the v1 serializers return. Plane-shaped DTOs, the pagination envelope and error bodies stay out ofthrust-contracts(the rule from #52). A reproduced 500 goes throughplane_500()from #51, or is a handled 500 with the pinned body, never a panic (ADR-0031 line 74). - Auth: look up
X-Api-Keyby its SHA-256 hash (ADR-0052 K1; #38 tries this shape). Return 401 for a missing key, and 403 with Plane's body for an invalid, expired or inactive one. Rate-limit per key; a 429 carries{"error_code":5900,"error_message":"RATE_LIMIT_EXCEEDED"}andRetry-After. SendX-RateLimit-RemainingandX-RateLimit-Reseton every response that passes authentication and permissions. On Cloudflare the binding does not report these values, so they are derived; if the countdown cannot match Plane's, record a deviation. - Harness home: vendor
oracle/from the fork branch intotools/oracle-v1/with aSOURCEfile that names the commit, or push the branch instead (the owner decides, Q-0122.4). Either way, add the harness to the ADR-0006 tooling register; theuvrule applies. - Scoped gate:
run_conformance.py --scope m1passes Schemathesis--include-tagfor the four tags (the script already passes--exclude-methodand--exclude-path-regex,:77,79). It restricts the register to the in-scope operations, counts staleness per (entry, operation), and uses floors measured on Plane for this scope. - Seed and corpus:
- A fixture loaded through
/internal/seed(crates/thrust-api/src/lib.rs:150-156) reproduces the uuid5 ids, names and seven tokens oforacle/scripts/seed.py, soseed-manifest.jsonapplies unchanged. Before every gate and control run, a reset script loads the fixture again. record_corpus.py --only(:427) records against Thrust, and the result is compared exchange by exchange with the committed corpus for the in-scope operations. Add the missingDELETE .../issues/{pk}/exchange to the corpus, recorded on Plane first.scripts/oracle-v1.sh <target>runs the gate and the corpus comparison, and is one of the planned cells ofgate.
- A fixture loaded through
- Schema diff: generate the 32 operations with utoipa, then run
oasdiff breakingagainst the pinned schema restricted to those operations. The EX-006 nullables are recorded exceptions. Never pass--open.
Acceptance criteria
-
scripts/oracle-v1.sh native-pgandscripts/oracle-v1.sh worker-cfend inVERDICT: PASSwithunaccepted=0,stale=0(per entry and operation) and the scoped floors met. The same scoped run against Plane passes too. - Control: with
run_controls.py --upstream <thrust>, the gate fails C1, C2 and C3 (each breaks one field ofGET .../states/,run_controls.py:33-44) on that operation, and passes C0. The corpus comparison catches C4 (a droppedid, which the schema cannot see). The results are committed. - After normalisation, the corpus comparison shows no difference for the in-scope exchanges in
projects,states,labels,work_items,paginationanderrors. A run that compares zero exchanges fails. Control: making state create return 201 makes it fail. - Contract tests pass on all four targets: no key gives 401; a bogus, expired or inactive key gives 403 with Plane's body; a create by a guest gives 403.
-
oasdiffreports no breaking change for the 32 operations, and the generated schema is committed. - The four list endpoints stay within the round-trip budget from #39.
References
- Review: .agents/plans/contrail/reviews/2026-10-19-fable-architecture-review.md (FR-01; §3 M1 row; FR-06)
- ADR-0031 (lines 23, 39, 60, 64-74), ADR-0032 (lines 29, 41, 70), ADR-0122 (lines 44, 77-79, 86, 90), ADR-0033 (lines 31, 79, 83; round-29 note), ADR-0052 (line 53), ADR-0006 (register), ADR-0034 (round-29 note)
research/0005-oracle-harness.md(lines 4-5, 49-55, 64-72, 88-89);spikes/0008-v1-oracle-harness.md; FEATURES §A5 (FEATURES.md:88-91), F-X06 (:135); Q-0122, Q-0122.4, Q-0120.3, Q-0033.2; DEVIATIONS C-2 (DEVIATIONS.md:32), D-002, D-007, D-013crates/thrust-api/src/lib.rs:47-49,54,82-99,150-156,269-293;crates/thrust-ports/src/lib.rs:208-211;crates/thrust-adapters-postgres/migrations/0001_init.sql:4-8,26-41- Plane fork branch
feat/plane-b6a-upstream-sync-oracle(72b2e01497):oracle/exceptions.yaml:12-23,25-44,45-89;oracle/harness/run_conformance.py:56-80,205-212;oracle/harness/run_controls.py:33-44;oracle/harness/record_corpus.py:427;oracle/NORMALISATION.md:23;oracle/scripts/seed.py;oracle/corpus/seed-manifest.json - Plane oracle (
oracle/v1-pin-20261018):apps/api/plane/api/middleware/api_authentication.py:32-38;apps/api/plane/api/rate_limit.py:12-48;apps/api/plane/settings/common.py:154
Blocked by: #35, #36, #47
Finding: FR-01
- Ngôn ngữ chính
- Rust
- Star
- 0
- Fork
- 0
- Merge trung bình
- 1 giờ 35 phút
- Pull request đã merge (30 ngày)
- 67
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Không có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của aRustyDev/thrust
-
area:process prio:p1 type:security
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 48/100
Maintainer thường phản hồi trong vòng 1 ngày
-
area:process bug prio:p1
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 38/100
Maintainer thường phản hồi trong vòng 1 ngày
-
area:process prio:p1
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 55/100
Maintainer thường phản hồi trong vòng 1 ngày
-
area:process prio:p1
Độ khó 4/5 1-2 ngày Mức phù hợp với người mới 55/100
Maintainer thường phản hồi trong vòng 1 ngày
-
area:process prio:p1
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 56/100
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của aRustyDev/thrust
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 68/100
Maintainer thường phản hồi trong vòng 1 ngày
-
bug
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
-
Clean master build fails in zune-jpeg error conversion and zero-IV array construction (patch)Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 78/100
CakeRepository/agentshangout#995 ·
-
area:frontend kind:bug priority:p3 ready
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 88/100
Maintainer thường phản hồi trong vòng 1 ngày