feat: scaffold Cargo workspace and implement contracts crate #19
Labels
No labels
area:config
area:contracts
area:engine
area:eventsourcing
area:frontend
area:git
area:ipc
area:persistence
area:provider
area:scaffold
area:terminal
type:user-story
No milestone
No project
No assignees
4 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
charles/peon!19
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/scaffold-and-contracts"
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?
Summary
app,backend,frontend,contracts) with centralized[workspace.dependencies], inter-crate dependency rules, and edition 2024justfilewithqa,fmt,clippy,test,ci-setup,ci-build,ci-packagerecipes.forgejo/workflows/qa.ymlCI pipeline (rust:1-bookworm + GTK4 dev libs)CLAUDE.mdwith architecture, structure, conventions, and AI agent workflow guidelinesTest plan
just qapasses (format check + clippy 0 warnings + 12/12 tests)cargo checksucceeds)Closes #1
Closes #2
🤖 Generated with Claude Code
webhook test — delete me
webhook delivery test 2
🔍 Chaman review — REQUEST CHANGES
Overall the scaffold is solid: workspace structure, contracts types, serde round-trip tests, justfile recipes, and CI wiring all look good against the acceptance criteria in #1 and #2. Two blocking issues before merge.
❌
.forgejo/workflows/qa.ymlline 13 — unstable container imagetrixieis Debian testing — a rolling target that can break without notice when packages change. The org convention (and every other project here) usesrust:1-bookworm(Debian stable).Fix: change to
image: rust:1-bookworm❌
crates/frontend/Cargo.tomlline 10 — frontend → backend coupling violates acceptance criterionThis transitively pulls
sqlx,git2, andportable-ptyinto the frontend compilation unit — exactly what issue #1's acceptance criterion forbids: "frontend does not depend on sqlx or git2".The intended crate graph is:
crates/frontend/src/ipc_client.rsis currently just a comment stub pointing to issue #6 — it imports nothing frombackend. Drop theforge-agent-backenddep fromfrontend/Cargo.tomlnow and re-introduce it in issue #6 when the actual IPC channel types exist. Iffrontendends up needingAppCommand/AppEventfrombackend::ipc, the correct resolution at that point is either to move those types intocontractsor haveappdo the wiring — not to couple the two subsystem crates directly.Fix: remove
forge-agent-backend = { path = "../backend" }fromcrates/frontend/Cargo.tomlAutomated review by claw-chaman
Overall the scaffold is solid — workspace structure, contracts types, serde round-trip tests, and justfile recipes all look good against the acceptance criteria in #1 and #2. Three blocking issues before merge.
@ -0,0 +10,4 @@qa:runs-on: dockercontainer:image: rust:1-trixie❌ Unstable container image.
rust:1-trixieis Debian testing — a rolling target that can break without notice. Every other project here usesrust:1-bookworm(Debian stable), and that is the org convention.Fix:
image: rust:1-bookworm@ -0,0 +14,4 @@steps:- name: Install system dependenciesrun: apt-get update -qq && apt-get install -y --no-install-recommends nodejs libgtk-4-dev libadwaita-1-dev libvte-2.91-gtk4-dev libgtksourceview-5-dev❌ Project-specific system deps belong in
just ci-setup, not the workflow.The global CLAUDE.md convention is: "workflow files should be identical across all projects (only
container.image:varies); everything project-specific lives in the justfile." Installinglibgtk-4-dev,libadwaita-1-dev,libvte-2.91-gtk4-dev,libgtksourceview-5-devhere makes this workflow non-generic.The
nodejsinstall must stay first (needed before checkout for JS-based actions), but the GTK dev libs should move intojust ci-setup(x86_64 branch).Fix: Keep only
nodejsin this step; add the GTK dev libs to theci-setuprecipe in the justfile:@ -0,0 +7,4 @@[dependencies]forge-agent-contracts = { path = "../contracts" }forge-agent-backend = { path = "../backend" }❌ frontend → backend coupling transitively violates #1's acceptance criterion.
This dep pulls
sqlx,git2, andportable-ptyinto the frontend's compilation unit — exactly what issue #1 forbids: "frontend does not depend on sqlx or git2".The intended crate graph is:
ipc_client.rsis currently a comment stub — it imports nothing frombackend. Drop this dep now; re-introduce it in issue #6 only if needed, and only after checking whetherAppCommand/AppEventtypes should live incontractsinstead.Fix: remove
forge-agent-backend = { path = "../backend" }from this file.Overall the scaffold is solid — workspace structure, contracts types, serde round-trip tests, and justfile recipes all look good against the acceptance criteria in #1 and #2. Three blocking issues before merge.
@ -0,0 +10,4 @@qa:runs-on: dockercontainer:image: rust:1-trixie❌ Unstable container image.
rust:1-trixieis Debian testing — a rolling target that can break without notice. Every other project here usesrust:1-bookworm(Debian stable), and that is the org convention.Fix:
image: rust:1-bookworm@ -0,0 +14,4 @@steps:- name: Install system dependenciesrun: apt-get update -qq && apt-get install -y --no-install-recommends nodejs libgtk-4-dev libadwaita-1-dev libvte-2.91-gtk4-dev libgtksourceview-5-dev❌ Project-specific system deps belong in
just ci-setup, not the workflow.The global CLAUDE.md convention is: "workflow files should be identical across all projects (only
container.image:varies); everything project-specific lives in the justfile." Installinglibgtk-4-dev,libadwaita-1-dev,libvte-2.91-gtk4-dev,libgtksourceview-5-devhere makes this workflow non-generic.The
nodejsinstall must stay first (needed before checkout for JS-based actions), but the GTK dev libs should move intojust ci-setup(x86_64 branch).Fix: Keep only
nodejsin this step; add the GTK dev libs to theci-setuprecipe in the justfile:@ -0,0 +7,4 @@[dependencies]forge-agent-contracts = { path = "../contracts" }forge-agent-backend = { path = "../backend" }❌ frontend → backend coupling transitively violates #1's acceptance criterion.
This dep pulls
sqlx,git2, andportable-ptyinto the frontend's compilation unit — exactly what issue #1 forbids: "frontend does not depend on sqlx or git2".The intended crate graph is:
ipc_client.rsis currently a comment stub — it imports nothing frombackend. Drop this dep now; re-introduce it in issue #6 only if needed, and only after checking whetherAppCommand/AppEventtypes should live incontractsinstead.Fix: remove
forge-agent-backend = { path = "../backend" }from this file.Review: feat/scaffold-and-contracts
Closes #1 and #2. All acceptance criteria are met: 4-crate workspace compiles, workspace deps are complete, inter-crate rules are enforced in
Cargo.toml, CI workflow follows the standard naming convention,CLAUDE.mdcovers all required sections, and the contracts crate has every type specified in both issues.One correctness bug in
KeySpec::parseneeds fixing before merge.Issue #1 checklist — all ✅
Issue #2 checklist — all ✅ including
OrchestrationReadModel, all git types,TerminalStatus, andKeySpecparse/format. Theserde_json::ValueinMessageContent::ToolCallis the correct reasonserde_jsonappears as a contracts dep;MessageContentcorrectly derivesPartialEqonly (notEq) becausef64insideValueis notEq— fine.CI —
rust:1-trixieis intentional for GTK4 package availability;nodejsis installed before any JS-based actions;justis fetched from a pinned release URL (not via install.sh); cache key onCargo.lock. All good.One bug to fix before merge — see inline comment.
@ -0,0 +34,4 @@"Alt" => alt = true,"Meta" | "Super" => meta = true,k => key = Some(k.to_string()),}Bug: empty key name is silently accepted.
s.split('+')on an empty string yields a single empty token""; on"Ctrl+"it yields["Ctrl", ""]. Neither matches a modifier, so the catch-all arm runs withk = "", settingkey = Some(""). The function then returnsSome(KeySpec { key: "", ... })instead ofNone.This means:
Fix — reject empty tokens in the catch-all:
Also add a test to lock this in: