Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 19 additions & 20 deletions .codebuddy/automations/fpt-cli/memory.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
# fpt-cli Automation Memory

## Last Run: 2026-03-26 (tenth pass — add entity relationship write + entity share)
## Last Run: 2026-03-26 (eleventh pass — entity relationship delete)

### Project State
- **Total CommandSpecs**: 67 (all registered in capability.rs)
- **Total Tests**: 274+ across test files in 3 crates (all passed)
- **ShotGrid API Coverage**: Expanded — added 3 more REST API endpoints
- **Total CommandSpecs**: 68 (all registered in capability.rs)
- **Total Tests**: 278+ across test files in 3 crates (all passed)
- **ShotGrid API Coverage**: Expanded — completed relationship CRUD surface
- **Code Quality**: Zero clippy warnings, zero fmt diffs, all tests passing on all platforms

### What Was Done This Run
- Created branch `feat/integrate-remaining-api-endpoints` from `origin/main`
- **Identified 3 ShotGrid REST API endpoints not yet integrated**:
1. `entity_relationship_create` — POST /entity/{type}/{id}/relationships/{field}
2. `entity_relationship_update` — PUT /entity/{type}/{id}/relationships/{field}
3. `entity_share` — POST /entity/{type}/{id}/_share
- **Added 3 new transport trait methods** with REST implementations
- **Added 3 new app layer methods** with input validation (relationship writes require `data` field, share requires JSON object)
- **Added 3 new CLI commands** (EntityCommands::RelationshipCreate, RelationshipUpdate, Share)
- **Added 3 new CommandSpecs**: `entity.relationship-create`, `entity.relationship-update`, `entity.share`
- **Wired all commands in runner.rs**
- **Added 12 new tests**: 8 app command tests (delegation + validation) + 1 capabilities test + 3 REST transport tests
- Created branch `feat/entity-relationship-delete` from `origin/main`
- **Identified `entity_relationship_delete` as the last feasible API endpoint to integrate**:
- DELETE /entity/{type}/{id}/relationships/{field} — removes links from a multi-entity relationship field
- **Added 1 new transport trait method** with REST implementation (DELETE with JSON body)
- **Added 1 new app layer method** with input validation (requires `data` field, same as create/update)
- **Added 1 new CLI command** (EntityCommands::RelationshipDelete)
- **Added 1 new CommandSpec**: `entity.relationship-delete`
- **Wired command in runner.rs**
- **Added 4 new tests**: 3 app command tests (delegation + 2 validation) + 1 REST transport test
- Updated all 6 mock transport impls across 4 test files
- Updated README.md and README_zh.md with new commands and test coverage
- Net change: +707/-25 across 13 files
- Net change: +248/-23 across 14 files
- All CI checks passed (9/9: fmt, clippy, hakari, test on all 3 platforms, cross-platform builds, code coverage)
- PR #99 squash-merged to main
- PR #100 squash-merged to main

### Previous Runs
- **Tenth pass**: entity relationship write + entity share. PR #99 merged.
- **Ninth pass**: preferences update + note reply update/delete. PR #98 merged.
- **Eighth pass**: Exposed remaining unregistered CLI commands (user.current, note.reply-read, filmstrip.url). PR #94 merged.
- **Seventh pass**: self_update map_err consolidation + edge-case tests. PR #92 merged.
Expand All @@ -44,11 +43,11 @@
- Server-side `_batch` API (POST /api/v1/entity/_batch) — current batch is client-side orchestration
- Thumbnail/image upload (PUT /entity/{type}/{id}/image) — only GET url exists
- Actual file upload via S3 presigned URL flow — only upload_url is implemented
- Entity relationship delete (DELETE /entity/{type}/{id}/relationships/{field}) — requires body with entity links to remove
- _(entity relationship delete is now implemented — relationship CRUD is complete)_

### Architecture Notes
- Three-crate workspace: `fpt-cli` (binary), `fpt-core` (shared types), `fpt-domain` (business logic)
- `ShotgridTransport` trait with 48 async methods — all fully implemented in `RestTransport`
- 67 CommandSpecs registered in capability.rs — complete CLI surface
- `ShotgridTransport` trait with 49 async methods — all fully implemented in `RestTransport`
- 68 CommandSpecs registered in capability.rs — complete CLI surface
- `RecordingTransport` mock used in all domain tests
- Batch operations use `futures::stream::buffer_unordered` with configurable concurrency (default 8, max 32)
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 13 additions & 5 deletions crates/fpt-domain/src/transport.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ const ENV_FPT_DEBUG: &str = "FPT_DEBUG";
/// Environment variable for overriding the maximum number of retry attempts.
const ENV_FPT_MAX_RETRIES: &str = "FPT_MAX_RETRIES";

/// Error message used when the in-memory token cache `Mutex` is poisoned.
const TOKEN_CACHE_POISONED: &str = "token cache is poisoned";

/// Safety margin (in seconds) subtracted from the access-token TTL so that
/// the token is refreshed before it actually expires on the server.
const TOKEN_EXPIRY_MARGIN_SECS: u64 = 30;
Expand Down Expand Up @@ -486,7 +489,7 @@ impl RestTransport {
});

let mut cache = self.token_cache.lock().map_err(|_| {
AppError::internal("token cache is poisoned").with_operation("write_token_cache")
AppError::internal(TOKEN_CACHE_POISONED).with_operation("write_token_cache")
})?;
*cache = Some(CachedAccessToken {
cache_key: Self::token_cache_key(config),
Expand Down Expand Up @@ -1529,7 +1532,7 @@ pub fn entity_collection_path(entity: &str) -> String {
output
}

pub fn plan_entity_create(api_version: &str, entity: &str, body: Value) -> RequestPlan {
pub(crate) fn plan_entity_create(api_version: &str, entity: &str, body: Value) -> RequestPlan {
RequestPlan {
transport: "rest",
method: "POST",
Expand All @@ -1544,7 +1547,12 @@ pub fn plan_entity_create(api_version: &str, entity: &str, body: Value) -> Reque
}
}

pub fn plan_entity_update(api_version: &str, entity: &str, id: u64, body: Value) -> RequestPlan {
pub(crate) fn plan_entity_update(
api_version: &str,
entity: &str,
id: u64,
body: Value,
) -> RequestPlan {
RequestPlan {
transport: "rest",
method: "PUT",
Expand All @@ -1560,7 +1568,7 @@ pub fn plan_entity_update(api_version: &str, entity: &str, id: u64, body: Value)
}
}

pub fn plan_entity_delete(api_version: &str, entity: &str, id: u64) -> RequestPlan {
pub(crate) fn plan_entity_delete(api_version: &str, entity: &str, id: u64) -> RequestPlan {
RequestPlan {
transport: "rest",
method: "DELETE",
Expand All @@ -1579,7 +1587,7 @@ pub fn plan_entity_delete(api_version: &str, entity: &str, id: u64) -> RequestPl
}
}

pub fn plan_entity_revive(entity: &str, id: u64) -> RequestPlan {
pub(crate) fn plan_entity_revive(entity: &str, id: u64) -> RequestPlan {
RequestPlan {
transport: "rpc",
method: "POST",
Expand Down
Loading
Loading