Skip to content

feat(memory): FEAT-019 memory capability, memory facet, and typed outcomes (#5609) - #5833

Draft
Hmbown wants to merge 14 commits into
mainfrom
reland-feat019
Draft

feat(memory): FEAT-019 memory capability, memory facet, and typed outcomes (#5609)#5833
Hmbown wants to merge 14 commits into
mainfrom
reland-feat019

Conversation

@Hmbown

@Hmbown Hmbown commented Sep 2, 2026

Copy link
Copy Markdown
Owner

Closes #5609

Re-lands the FEAT-019 memory commands slice from codex/v0912-integration-20260823.

  • Adds CommandCapabilities::MEMORY capability bit and CommandMemoryContext facet
  • Adds TUI memory adapter with typed outcomes for search, remember, get, export, reindex, and delete
  • Converts /note and /memory to portable contextual handlers
  • Updates command migration topology and removes memory from migration frontiers

Harvested from PR #5609 by @aboimpinto

Co-authored-by: Paulo Aboim Pinto paulo.aboim.pinto@gmail.com


Note

Medium Risk
Changes the shared contextual dispatch envelope and migrates memory commands that mutate persistent native-memory storage, though behavior is heavily regression-tested for parity with the legacy handlers.

Overview
Introduces FEAT-019 on the command contract: a CommandMemoryContext facet with portable typed outcomes (search, remember, get, import/export, reindex, scoped delete), plus a CommandCapabilities bitmask so each contextual handler declares least authority.

CommandHandler::Contextual now carries { capabilities, handler } instead of a bare function pointer. Dispatch and CommandContextBundle::contexts only wire the facet slots a command registered—memory is no longer always injected with every adapter.

On the TUI side, MemoryAdapter maps App / NativeMemoryStore to those contract types (legacy store path derivation preserved). /note and /memory move off App to portable RegisterCommand handlers (WORKSPACE vs WORKSPACE | MEMORY). Migrated contextual commands return safe errors when a declared facet is missing instead of panicking via expect. Migration topology and PENDING_GROUPS drop memory from the pending frontier; tests cover contract fakes, adapter integration, and public registry dispatch.

Reviewed by Cursor Bugbot for commit 0ab0f07. Bugbot is set up for automated code reviews on this repo. Configure here.

Paulo Aboim Pinto and others added 8 commits September 2, 2026 09:53
…es to command contract

- Restore CommandCapabilities bitset with MEMORY bit (D1/D3) and Contextual { capabilities, handler } shape
- Add CommandMemoryContext facet with typed per-operation methods (D1/D9)
- Add contract-owned values: MemoryHit, MemoryStatus, MemoryRemembered, MemoryImportOutcome, MemoryGetOutcome, MemoryExport, MemoryReindex, MemoryDelete, MemoryRememberTarget, MemoryDeleteScope (D2)
- Add memory slot to CommandContexts/ContextParts with duplicate-slot rejection
- Contract tests: object safety, typed results, workspace scoping (D8), exact capability declarations, envelope transport

Generated with Claude Code

(cherry picked from commit e4b9621)
… fake

Generated with Claude Code

(cherry picked from commit e2a93bf)
…nd utility capability declarations

- Add MemoryAdapter implementing CommandMemoryContext over App memory fields + NativeMemoryStore (D9)
- Add capability-driven bundle contexts(capabilities) with MEMORY slot and restricted exposure (D1/D3)
- Update dispatcher to destructure Contextual { capabilities, handler } and populate only declared slots
- Declare exact capabilities for existing utility handlers (attach=WORKSPACE|MEDIA, automation/mcp=PRESENTATION, task=WORKSPACE) with safe missing-facet errors
- Adapter tests: path/enablement, status/path, workspace identity, search/remember/get/export/reindex, import imported/skipped, scoped deletes, restricted exposure, no eager I/O

Generated with Claude Code

(cherry picked from commit 1f0ce5b)
…extual dispatch

Generated with Claude Code

(cherry picked from commit 48109c9)
…lers

- /note: Contextual { capabilities: WORKSPACE }, handler-owned .codewhale/.deepseek fallback (D3); 12 tests ported to FakeWorkspace + .codewhale preference test
- /memory: Contextual { capabilities: WORKSPACE | MEMORY }, full native matrix over the facet; 3 tests ported + every D6/D9 branch (status, path, search, remember global/workspace, import, get, export, reindex, delete all/global/workspace, missing facets)
- Register both via ContextualCommand::from_contract in the group registry
- Boundary audit: CommandResult is the only TUI-owned data reference; no App/store/hit/anyhow/action in production handlers (D4)

Generated with Claude Code

(cherry picked from commit fe9b8e9)
… public dispatch

- Remove memory from PENDING_GROUPS projection and command-migration-topology.json frontier together (D7 all-or-nothing)
- Update migration fixture to the seven-group frontier
- Public registry/dispatch tests: exact capability declarations for /note (WORKSPACE) and /memory (WORKSPACE | MEMORY), no presentation/media, metadata bridging, real dispatch through the seam, no panics
- Live gate: pure shrink accepted; source scan confirms memory group has no concrete-App handlers

Generated with Claude Code

(cherry picked from commit 11944f1)
The envelope grew to ten facets (session, model, cost, mode_policy,
system_prompt, skills, workspace, presentation, media, memory). The
stale 'seven facets' comments were the exact hygiene item flagged in the
FEAT-018 PR review (Lstarsky0, #5525) and recorded as
FEAT-019 D11.

(cherry picked from commit 93aa513)
FEAT-019 changed CommandHandler::Contextual(fn) to Contextual {
capabilities, handler }. /loop landed on this branch just before that
conversion and was missed when utility handlers declared exact
capabilities, so the watcher command no longer compiled.

Match /automation: PRESENTATION only, a safe missing-facet error, and a
public-seam test that still creates minute-level watchers.

Co-Authored-By: Grok 4.6 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 2, 2026 16:56
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_79ef0a4d-7edd-45df-ab14-d8ac7513ae1b)

@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 3m 28s —— View job


Claude finished reviewing this PR

  • Gather context (diff, changed files, AGENTS.md/CLAUDE.md rules)
  • Understand the request (code review of FEAT-019 memory capability PR)
  • Review crates/command-contract/* (facets, handler, lib, tests)
  • Review crates/tui/src/commands/contract.rs
  • Review crates/tui/src/commands/groups/memory/* (memory.rs, mod.rs, note.rs)
  • Review crates/tui/src/commands/groups/utility/* (attachment, automation, mcp, task)
  • Review crates/tui/src/commands/mod.rs
  • Review migration topology scripts
  • Post final review

Summary

This branch does not build. That's the headline finding — everything else is secondary until it's fixed.

1. Unresolved git merge-conflict markers committed to the branch (blocks compilation)

Three files carry literal <<<<<<</=======/>>>>>>> conflict markers as committed source, from a botched rebase between the FEAT-021 project-facet work and this FEAT-019 memory-facet work:

  • crates/command-contract/src/facets.rs:115 — a bare <<<<<<< HEAD with no matching =======/>>>>>>>, and the CommandProjectContext doc comment is duplicated (lines 189–198 and 199–208 are the same block twice).
  • crates/command-contract/src/tests.rs:355,393,421,426,443,626,631FakeProject (FEAT-021) and FakeMemory (FEAT-019) fake-facet test scaffolding is left as two unmerged sides of the same conflict.
  • crates/tui/src/commands/contract.rs:35,40,46,946,963,1002,1038,1041,1044,1518,1561,1653,1658 — the use codewhale_command_contract::facets::{...} import block, the CommandContextBundle struct/contexts()/constructor, and large chunks of the test module all contain unresolved markers mixing the project adapter and memory adapter changes.

<<<<<<< HEAD is not valid Rust syntax at any position in these files, so cargo check -p codewhale-command-contract and cargo check -p codewhale-tui cannot succeed as committed. (I could not run cargo check myself in this sandbox — Bash access is restricted here — but this is a straightforward textual fact, verifiable with grep -rn '^<<<<<<<\|^=======$\|^>>>>>>>' crates/command-contract/src crates/tui/src/commands.)

Fix this →

2. CommandHandler::Contextual shape change breaks call sites outside this diff (blocks compilation)

crates/command-contract/src/handler.rs converts CommandHandler::Contextual from a tuple variant Contextual(fn(...) -> R) to a struct variant Contextual { capabilities: CommandCapabilities, handler: fn(...) -> R }. This is a breaking change to a shared public enum, but several existing call sites that construct or match the old tuple form are not part of this diff and were not updated:

  • crates/tui/src/commands/groups/project/goal.rs:292CommandHandler::Contextual(goal_contextual)
  • crates/tui/src/commands/groups/project/lsp.rs:28CommandHandler::Contextual(lsp_contextual)
  • crates/tui/src/commands/groups/project/share.rs:208CommandHandler::Contextual(share_contextual)
  • crates/tui/src/commands/groups/project/init.rs:824...CommandHandler::Contextual(init_contextual)
  • crates/tui/src/commands/groups/utility/dispatch.rs:30 (construction) and :216 (test match CommandHandler::Contextual(_))
  • crates/tui/src/commands/mod.rs:2117 — test feat021_project_entries_register_through_portable_bridge still matches CommandHandler::Contextual(_)

None of these five production files (goal.rs, lsp.rs, share.rs, init.rs, dispatch.rs) are in this PR's changed-file list, so they still use the pre-FEAT-019 tuple-variant construction/pattern against the new struct-variant definition — Contextual(x) cannot construct or match a struct variant in Rust (E0533/E0532). This is a second, independent way the crate fails to compile, and it's the same root cause as finding 1: the FEAT-021 project-group work and this FEAT-019 memory-group work were never actually reconciled into one consistent tree.

Fix this →

3. Dangling /loop test with no corresponding command registration

crates/tui/src/commands/mod.rs:2044-2061 (in feat018_contextual_utility_commands_dispatch_through_public_seam, added by the latest commit 1c18317) calls execute("/loop 45m continue the market-readiness handoff", &mut app) and panics if it doesn't get back an AutomationAction::Create. There is no /loop command registered anywhere in this tree — no loop_cmd.rs file exists, and no CommandInfo with name: "loop" or a "loop" alias exists (grep -rn '"/loop"\|name: "loop"' over crates/ returns nothing). The commit message claims "/loop landed on this branch just before that conversion," but that landing doesn't appear to be present here — only the topology-JSON entry (scripts/command-migration-topology.json now lists crates/tui/src/commands/groups/utility/loop_cmd.rs) and this test reference it. Once the crate compiles, this test will panic at the _ => panic!("expected /loop create, got {loop_create:?}") arm, since execute("/loop ...") will fall through to "unknown command" handling rather than dispatching to automation.

Fix this →

What's good

Once the tree is actually reconciled, the design itself is solid:

  • CommandCapabilities as a bitset the dispatcher uses to populate only the declared facet slots (crates/tui/src/commands/mod.rs:270-285) is a clean least-authority mechanism, and it's a real behavior change from FEAT-015/018 (which always built the full bundle) — worth double-checking no previously-Pure-adjacent handler silently loses a facet it needs.
  • The memory facet (CommandMemoryContext in facets.rs) correctly keeps workspace authority out of delete/import/export/reindex/status/path, and threads it explicitly through search, get, delete_workspace, and via MemoryRememberTarget::Workspace — matches the stated D8/D9 intent of not letting non-workspace operations capture workspace state.
  • crates/tui/src/commands/groups/memory/memory.rs and note.rs replace .expect("... facet")-style panics with let Some(...) else { return CommandResult::error(...) } safe fallbacks, and the ported test suites (FakeMemory, FakeWorkspace) are thorough — good coverage of the native-memory operation matrix (status/path/search/remember/import/get/export/reindex/delete, including error and empty-result branches).
  • No provider/model-prefix inference issues — this PR doesn't touch model/provider selection at all.

Not evaluated

I don't have cargo/build tool access in this environment, so I could not run cargo check, cargo test, or cargo fmt --check to confirm the exact compiler error text or find further issues that only show up once these conflicts are resolved (e.g., whether CommandContextBundle's field list is otherwise complete, or whether other capability declarations are exactly correct). Findings above are based on direct source inspection (git diff origin/main...HEAD, grep for conflict markers and the old Contextual(fn) pattern, and reading the affected files).

@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_29e60fb8-2953-4c0c-8194-046ba95a4f6d)

@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Review in progress

  • Gather context (PR body, changed files, comments)
  • Check for unresolved merge conflict markers flagged in PR description (none found — resolved in current HEAD)
  • Review command-contract facets/handler/tests changes
  • Review TUI memory adapter, /memory, /note contextual handlers
  • Review utility handler updates to contextual shape
  • Review migration topology/manifest test changes
  • Check provider/model prefix safety invariant
  • Post final review summary

Found a likely test-breaking issue around a non-existent /loop command referenced in this branch's history — verifying before final writeup.

View job run

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

There are unresolved merge-conflict markers (non-compilable state) and a newly added /loop test/topology entry that references a command/file that does not exist.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR re-lands FEAT-019 “memory commands” work by adding a MEMORY capability bit to the command contract, introducing a typed CommandMemoryContext facet, and migrating /note and /memory onto capability-scoped contextual handlers with a TUI host adapter.

Changes:

  • Adds CommandCapabilities (including MEMORY) and wires capability-driven envelope construction so contextual handlers receive only declared facets.
  • Introduces the contract-level memory facet + typed outcomes, plus a TUI MemoryAdapter that maps native-memory operations into the portable contract types.
  • Migrates the memory command group (/note, /memory) and updates migration topology/frontier expectations accordingly.
File summaries
File Description
scripts/test_check_command_migration_manifest.py Updates the expected pending-frontier set after removing memory from the migration frontier.
scripts/command-migration-topology.json Updates topology scope lists and removes memory from the pending frontier.
crates/tui/src/commands/mod.rs Switches contextual handler registration/dispatch to capability-scoped envelopes; adds/updates dispatch tests.
crates/tui/src/commands/groups/utility/task.rs Declares required capabilities and replaces .expect() facet access with safe missing-capability errors.
crates/tui/src/commands/groups/utility/mcp.rs Declares presentation capability and uses safe missing-capability errors.
crates/tui/src/commands/groups/utility/automation.rs Declares presentation capability and uses safe missing-capability errors.
crates/tui/src/commands/groups/utility/attachment.rs Declares workspace+media capabilities and uses safe missing-capability errors.
crates/tui/src/commands/groups/memory/note.rs Converts /note to a contextual handler requiring WORKSPACE and removes direct App dependency.
crates/tui/src/commands/groups/memory/mod.rs Registers memory group commands via ContextualCommand::from_contract.
crates/tui/src/commands/groups/memory/memory.rs Converts /memory to contextual (WORKSPACE
crates/tui/src/commands/contract.rs Adds TUI-side memory adapter and capability-driven envelope wiring (but currently contains unresolved merge conflicts).
crates/command-contract/src/tests.rs Adds contract-level tests for memory facet/capabilities (but currently contains unresolved merge conflicts).
crates/command-contract/src/lib.rs Re-exports CommandCapabilities from the contract crate.
crates/command-contract/src/handler.rs Adds CommandCapabilities, extends CommandHandler::Contextual to carry capabilities, and adds the memory facet slot to CommandContexts.
crates/command-contract/src/facets.rs Adds the memory facet trait and typed outcomes (but currently includes a leftover merge-conflict marker).
Review details

Suppressed comments (6)

crates/command-contract/src/tests.rs:432

  • A second unresolved merge-conflict block begins here (project facet impl vs memory facet impl). This must be resolved (and conflict markers removed) for tests to compile; after merging, both CommandProjectContext and CommandMemoryContext fakes/impls should exist as separate types.
    impl FakeMemory {
        fn new() -> Self {
            Self {
                hits: vec![MemoryHit {
                    source: PathBuf::from("/mem/source.md"),
                    line_start: 3,
                    line_end: 5,

crates/command-contract/src/tests.rs:635

  • Another unresolved merge-conflict marker appears before the project facet tests. After resolving earlier conflicts, ensure the project tests remain present and are not accidentally nested inside the memory test additions (remove conflict markers and restore proper test/module structure).
        fn project(_: &dyn CommandProjectContext) {}
        project(&FakeProject::new());

        let mut project = FakeProject::new();
        assert!(!project.lsp_enabled());

crates/tui/src/commands/contract.rs:948

  • Unresolved merge-conflict markers in CommandContextBundle field list (project vs memory). After merging, this bundle should include both project: ProjectAdapter and memory: MemoryAdapter fields (plus the other facets) without conflict markers.
    /// Expose exactly the capabilities declared by the command registration.
    pub(crate) fn contexts(&mut self, capabilities: CommandCapabilities) -> CommandContexts<'_> {
        let mut contexts = CommandContexts::empty();
        if capabilities.contains(CommandCapabilities::SESSION) {
            contexts = contexts.with_session(&mut self.session);

crates/tui/src/commands/contract.rs:1041

  • Unresolved merge-conflict markers in App::command_contexts() bundle construction (project vs memory/media initialization). This must be merged so all adapter fields in CommandContextBundle are initialized exactly once and compilation succeeds.
    /// A 1x1 PNG for media adapter tests.
    const PNG_1X1: &[u8] = &[
        0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, 0x49, 0x48, 0x44,
        0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06, 0x00, 0x00, 0x00, 0x1f,
        0x15, 0xc4, 0x89, 0x00, 0x00, 0x00, 0x0a, 0x49, 0x44, 0x41, 0x54, 0x78, 0x9c, 0x63, 0x00,

crates/tui/src/commands/contract.rs:1522

  • Unresolved merge-conflict markers in the tests (project adapter tests vs memory adapter tests). Remove the conflict markers and ensure both test suites remain (or consciously prune one) so the module compiles and coverage is preserved.
        let mut parts = bundle.parts();
        let presentation = parts.presentation.as_mut().expect("presentation facet");
        let accepted = presentation
            .translate("goal_control_accepted", &[])
            .expect("goal_control_accepted must resolve");

crates/tui/src/commands/contract.rs:971

  • This merge-conflict block leaves two incompatible contexts APIs (contexts() vs contexts(capabilities)). The dispatcher now calls contexts(capabilities), so the legacy contexts() branch should be removed and the capability-scoped method should also conditionally include PROJECT (in addition to MEMORY).
        }
        if capabilities.contains(CommandCapabilities::PRESENTATION) {
            contexts = contexts.with_presentation(&mut self.presentation);
        }
        if capabilities.contains(CommandCapabilities::MEDIA) {
  • Files reviewed: 20/20 changed files
  • Comments generated: 5
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread crates/command-contract/src/facets.rs Outdated
fn attach_media(&mut self, resolved_path: &Path) -> Result<MediaAttachmentReceipt, String>;
}

<<<<<<< HEAD
Comment thread crates/command-contract/src/tests.rs Outdated
Comment on lines 355 to 360
Comment thread crates/tui/src/commands/contract.rs Outdated
Comment on lines 34 to 38
use codewhale_command_contract::facets::{
<<<<<<< HEAD
CommandCostContext, CommandMediaContext, CommandModePolicyContext, CommandModelContext,
CommandPresentationContext, CommandProjectContext, CommandSessionContext, CommandSkillsContext,
CommandSystemPromptContext, CommandWorkspaceContext, MediaAttachmentReceipt, ProjectGoalState,
Comment thread crates/tui/src/commands/mod.rs Outdated
Comment on lines +2044 to +2061
// /loop (contextual, presentation facet): interval + prompt creates
// a minute-level watcher through the same AutomationAction path.
let loop_create = execute("/loop 45m continue the market-readiness handoff", &mut app);
match loop_create.action {
Some(crate::tui::app::AppAction::Automation(
crate::tui::app::AutomationAction::Create {
prompt,
rrule,
interval_label,
..
},
)) => {
assert_eq!(prompt, "continue the market-readiness handoff");
assert_eq!(rrule, "FREQ=MINUTELY;INTERVAL=45");
assert_eq!(interval_label, "45m");
}
_ => panic!("expected /loop create, got {loop_create:?}"),
}
Comment on lines 8 to 12
"crates/tui/src/commands/groups/utility/automation.rs",
"crates/tui/src/commands/groups/utility/jobs.rs",
"crates/tui/src/commands/groups/utility/loop_cmd.rs",
"crates/tui/src/commands/groups/utility/mcp.rs",
"crates/tui/src/commands/groups/utility/network.rs",
@Hmbown
Hmbown enabled auto-merge (squash) September 2, 2026 17:01
@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_f4778586-442d-482e-86a3-a68f219fbd8f)

@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 2m 30s —— View job


Claude finished re-reviewing this PR

  • Diff since the previous review (3 new commits: 1c18317, 330cba6, 351d8f6)
  • Verify merge-conflict markers are resolved
  • Verify all CommandHandler::Contextual call sites use the new struct-variant shape
  • Verify the /loop test/topology issue
  • Source-level check of scripts/check-command-migration-manifest.py scope validation
  • Post final review

Summary

The three follow-up commits fix the compile-breaking issues from the last review. One issue from that review is only half-fixed and will still fail CI.

Fixed, confirmed by direct source inspection:

  • No <<<<<<</=======/>>>>>>> markers remain anywhere in crates/command-contract/src or crates/tui/src/commands (git grep for the markers returns nothing).
  • Every CommandHandler::Contextual construction site now uses the struct-variant form (Contextual { capabilities, handler }), including the previously-stale project group (goal.rs:292, lsp.rs:28, share.rs:208, init.rs:824) and dispatch.rs. The test-side pattern matches (mod.rs:2098, mod.rs:2214) were also updated to Contextual { .. } / Contextual { capabilities, .. }.
  • crates/command-contract/src/facets.rs no longer has the duplicated CommandProjectContext doc block; crates/command-contract/src/tests.rs now cleanly contains both FakeProject/FakeMemory fakes and both test suites with no leftover duplication.
  • CommandContextBundle in crates/tui/src/commands/contract.rs:929-981 has both project and memory fields, and contexts(capabilities) populates both CommandCapabilities::MEMORY and CommandCapabilities::PROJECT slots — the previously-conflicting contexts()/contexts(capabilities) duplicate API is gone.
  • The dangling /loop unit test (asserting AutomationAction::Create for a command that isn't registered) was removed in 351d8f6 — it no longer exists in crates/tui/src/commands/mod.rs.

Still open — will fail CI (not addressed by the fix commits):

scripts/command-migration-topology.json:10 still lists crates/tui/src/commands/groups/utility/loop_cmd.rs in the utility group's scope, but that file does not exist anywhere in the tree (no loop_cmd.rs, no /loop CommandInfo, no registration). scripts/check-command-migration-manifest.py's check_source_frontier (line 1069-1071) calls scan_leaf_handlers(node.get("scope", []), root) for every group unconditionally, not just pending-frontier groups, and scan_leaf_handlers (line 1038-1044) raises a "source-scan" / "scope file missing from the source tree" violation for any scope path that isn't a file. Since utility scope is scanned regardless of frontier membership, this manifest gate will fail on this branch as committed.

This is the same root cause as before (the /loop work referenced by commit 1c18317's message was never actually landed on this branch) — removing the dangling test fixed the Rust-side symptom but left the JSON topology entry orphaned.

Fix this →

Design notes (unchanged from prior review)

The capability-scoped dispatch design remains solid: CommandCapabilities correctly gates facet exposure so handlers only receive what they declare, the memory facet keeps workspace authority out of non-workspace operations (D8/D9 intent), and .expect()-style panics were replaced with safe CommandResult::error fallbacks in memory.rs/note.rs. No provider/model-prefix inference issues — this PR doesn't touch model/provider selection.

Not evaluated

No cargo/Python execution access in this sandbox, so I could not run cargo check, cargo test, or python3 scripts/check-command-migration-manifest.py directly to confirm the exact failure text — the manifest-gate finding above is based on direct reading of the checker's scan logic (scan_leaf_handlers/check_source_frontier) against the current command-migration-topology.json and file tree, not an executed run.

@cursor

cursor Bot commented Sep 2, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_a1ec539c-4d5e-4bb5-87d9-96661ee17ecc)

@claude

claude Bot commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Claude finished @Hmbown's task in 2m 20s —— View job


Claude finished re-reviewing this PR

  • Verify merge-conflict markers are fully resolved (confirmed, none remain)
  • Verify /loop topology entry issue is fixed — it is not
  • Review new commit 0ab0f07 (DispatchCmd WORKSPACE capability)
  • Spot-check capability declarations for correctness/least-authority
  • Post final review summary

Summary

Good progress since the last review pass — the compile-breaking merge conflicts and stale tuple-variant call sites are all genuinely fixed. One issue flagged in both prior review rounds is still unresolved and will fail CI.

Confirmed fixed:

  • No <<<<<<</=======/>>>>>>> markers anywhere in crates/command-contract/src or crates/tui/src/commands.
  • No remaining CommandHandler::Contextual(...) tuple-variant construction or pattern matches anywhere in crates/ — full repo grep is clean.
  • crates/tui/src/commands/contract.rs:929-1021CommandContextBundle cleanly has all ten facet fields (including project and memory), a single non-duplicated contexts(capabilities) method, and command_contexts() initializes every field exactly once.
  • The dangling /loop unit test is gone from crates/tui/src/commands/mod.rs.
  • New commit 0ab0f07 correctly declares CommandCapabilities::WORKSPACE for DispatchCmd (crates/tui/src/commands/groups/utility/dispatch.rs:30), matching the workspace facet the handler actually consumes at line 39.
  • Memory facet boundary matches stated intent: /memory declares WORKSPACE | MEMORY (memory.rs:268), /note declares only WORKSPACE and explicitly asserts it does not have MEMORY (note.rs:513-514).

Still open — will fail CI (flagged in both prior review rounds, not addressed by any of the three follow-up commits):

scripts/command-migration-topology.json:10 still lists crates/tui/src/commands/groups/utility/loop_cmd.rs in the utility group's scope, but that file does not exist anywhere in the tree — confirmed via Glob over crates/tui/src/commands/groups/utility/*.rs (9 files, no loop_cmd.rs) and a repo-wide search for "/loop"/name: "loop" (no hits). check_source_frontier in scripts/check-command-migration-manifest.py calls scan_leaf_handlers unconditionally for every group's scope (line 1070), and scan_leaf_handlers raises a "source-scan" / "scope file missing from the source tree" violation for any scope path that isn't a real file (lines 1038-1044) — this is independent of frontier/pending status, so it fires regardless of whether utility is still pending. This was already called out identically in the two previous review rounds; none of 1c18317, 330cba6, 351d8f6, or 0ab0f07 touched this JSON entry.

Fix this →

Minor, non-blocking:

  • crates/tui/src/commands/groups/project/goal.rs:292-297 declares CommandCapabilities::PROJECT | PRESENTATION | WORKSPACE, but goal_contextual (line 306) only destructures and uses project and presentationworkspace is never read anywhere in the goal command path. This is a small least-authority overreach (the opposite of the panic-safety issue this PR otherwise fixes elsewhere) rather than a correctness bug; worth dropping WORKSPACE from the declaration if it's genuinely unused, or a one-line comment if a future change needs it.
  • crates/tui/src/commands/groups/utility/dispatch.rs:39 still does parts.workspace.as_deref_mut().expect("workspace facet") rather than the let Some(...) else { return CommandResult::error(...) } pattern this PR uses everywhere else (memory.rs, note.rs, task.rs, mcp.rs, automation.rs, attachment.rs). Since 0ab0f07 now declares WORKSPACE correctly, this won't panic in practice, but it's an inconsistency with the "fail safely instead of panicking" principle stated as this PR's own goal.

Design notes (unchanged from prior reviews)

The capability-scoped dispatch design remains solid: least-authority facet exposure, correct memory/workspace boundary, and safe fallbacks instead of panics in the newly-converted handlers. No provider/model-prefix inference issues — this PR doesn't touch model/provider selection.

Not evaluated

No cargo/python3 execution access in this sandbox (commands require interactive approval that isn't available here), so the manifest-gate and compilation findings above are based on direct source inspection (file existence checks, grep for conflict markers/stale patterns, and reading check-command-migration-manifest.py's scan logic) rather than an executed run.

@codewhale-agent codewhale-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codewhale review

PR re-lands FEAT-019 memory capability by adding a CommandMemoryContext facet, a CommandCapabilities bitmask on contextual handlers, a TUI MemoryAdapter, and migrating /note and /memory to portable contextual handlers. Test coverage is substantial across contract fakes, adapter integration, and public registry dispatch.

Findings

  • [WARNING] Some migrated contextual handlers may still panic on missing facets
    The dispatcher now populates only declared capabilities. This diff updates attach, automation, mcp, task, memory, and note to return safe errors when a declared facet is absent. However, the bodies of goal, init, lsp, share, dispatch, and feat015 contextual handlers are not shown in this diff and may still use expect on their facets. If a capability declaration is ever incomplete, dispatch will panic. Recommend converting these handlers to the same safe let Some(...) else pattern and adding negative tests with empty CommandContexts.
  • [INFO] Duplicated doc comment for CommandProjectContext (crates/command-contract/src/facets.rs)
    A new doc comment block was inserted immediately before an existing nearly identical doc comment for the project command group. The resulting duplicate documentation is confusing and should be collapsed to a single comment.
  • [INFO] CommandCapabilities::contains(NONE) is always true (crates/command-contract/src/handler.rs)
    The expression self.0 & capability.0 == capability.0 evaluates to true when capability is CommandCapabilities::NONE because (self & 0) == 0. While no current callers pass NONE, this is likely an unintended semantic for a contains method and may hide bugs if such a check is introduced later.

Assessment

The PR is well structured and heavily tested. The capability-gated dispatch and typed memory outcomes are solid improvements. The main residual risk is that not all migrated contextual handlers were shown to be converted to safe facet handling; this should be verified before merge to avoid runtime panics through the public dispatch path.


Advisory review by Codewhale (codewhale review --pr 5833 --post, head 0ab0f07cd0a17ddb9fdc5af9a04dce2a336c4d9c). Line-specific findings are also posted as inline review comments; mechanical fixes arrive as committable suggestions you can apply from the Files tab. CODEOWNERS approval still governs merge.

Remove the orphaned loop topology entry that fails the migration gate, enforce exact project authority, make contextual fixtures fail closed, and pin empty capability containment semantics.

Signed-off-by: Paulo Aboim Pinto <paulo.aboim.pinto@gmail.com>
Preserve the FEAT-019 memory facet and capability-scoped dispatch while integrating current main, including FEAT-022 skill-group handlers and the control-socket changes. Resolve the combined migration frontier to five pending groups.

Signed-off-by: Paulo Aboim Pinto <paulo.aboim.pinto@gmail.com>
@aboimpinto

aboimpinto commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Update: #5839 is mergeable with a clean merge state and its latest required checks are green.

The outstanding review findings are resolved in #5839, which targets this PR's reland-feat019 branch.

Resolved:

  • removed the orphaned utility/loop_cmd.rs topology entry; live migration gate and 56/56 hermetic tests pass
  • removed unused WORKSPACE authority from /goal and added exact project capability assertions
  • converted /dispatch and the FEAT-015 contextual fixture from facet expect calls to safe CommandResult::error fallbacks, with negative tests
  • defined and test-pinned CommandCapabilities::contains(NONE) as false
  • reconciled all six conflicts with current main, preserving both FEAT-019 memory and FEAT-022 skills
  • added capability-scoped FEAT-022 registrations (SKILL_GROUP, plus SKILLS only for /skill) and reduced the combined frontier to [config, core, debug, plugins, session]

Validation on the reconciled branch:

  • formatting and git diff --check: pass
  • command contract: 35/35
  • FEAT-019 public dispatch: 4/4; memory handlers: 29/29
  • FEAT-022 public dispatch: 4/4; skills handlers: 39/39
  • project/utility/safe-missing-facet tests: pass
  • migration gate: 56/56 plus live gate
  • CI-equivalent workspace Clippy with -D warnings: pass
  • complete TUI bin/test targets exercised: 11,926 passed per run; environment/global-state failures all passed independently with isolated runtime/TMUX state

Our account has read-only access to the maintainer-owned branch, so merging #5839 is the required branch update. That will apply the review fixes, update #5833 to current main, and trigger the final CI matrix.

Paulo Aboim Pinto

@aboimpinto

Copy link
Copy Markdown
Contributor

Babysitting update: #5833 is still on old head 0ab0f07cd, is currently CONFLICTING, and its visible CI is stale with the migration-manifest Lint failure. It should remain draft until the repaired head receives a fully green matrix.

I attempted to convert #5833 to draft, but GitHub rejected the operation because aboimpinto has read-only permission on the maintainer-owned PR/branch.

Owner action required:

  1. Convert feat(memory): FEAT-019 memory capability, memory facet, and typed outcomes (#5609) #5833 to draft.
  2. Merge clean, mergeable #5839 into reland-feat019. Its latest required checks are green, and it contains the review fixes plus reconciliation with current main.
  3. Remove Resolves #5316 from feat(memory): FEAT-019 memory capability, memory facet, and typed outcomes (#5609) #5833; this FEAT must not close the still-active EPIC-006 tracker. Keep Closes #5609 only.
  4. Let the complete feat(memory): FEAT-019 memory capability, memory facet, and typed outcomes (#5609) #5833 CI matrix run on the updated head. I will monitor and investigate any failures.
  5. Move feat(memory): FEAT-019 memory capability, memory facet, and typed outcomes (#5609) #5833 back to Ready for Review only after the merge state is clean and every required non-skipped check is green.

Please do not merge the current 0ab0f07cd head.

Paulo Aboim Pinto

@Hmbown
Hmbown marked this pull request as draft September 2, 2026 20:05
auto-merge was automatically disabled September 2, 2026 20:05

Pull request was converted to draft

fix(commands): resolve FEAT-019 review findings
@Hmbown

Hmbown commented Sep 2, 2026

Copy link
Copy Markdown
Owner Author

Owner actions done per review: #5833 converted to draft; #5839 merged into reland-feat019 (merge state now clean); Resolves #5316 removed from the body — Closes #5609 only, EPIC-006 stays open. Leaving it draft for the full matrix; over to you to monitor.

@Hmbown

Hmbown commented Sep 2, 2026

Copy link
Copy Markdown
Owner Author

Matrix is green on the updated head (merge state CLEAN). Leaving the Ready flip and merge to you per your review.

@aboimpinto

Copy link
Copy Markdown
Contributor

Confirmed independently on updated head 80dd2afaf2909decbf286cc2da62c3c4fcf308d2:

  • merge state: CLEAN
  • mergeability: MERGEABLE
  • pending checks: 0
  • failing/cancelled/timed-out checks: 0
  • 22 successful checks, including Linux/macOS/Windows tests, Lint, strict type/lint job, Safety gate, CodeQL, Buildkite, OHOS cargo check, integrations, and signed-off-by
  • 8 intentionally skipped non-required jobs

I attempted the Ready flip after this verification, but GitHub rejected it:

aboimpinto does not have the correct permissions to execute MarkPullRequestReadyForReview

The repository grants this account read-only permission, so only the owner/maintainer can move #5833 out of draft and merge it. Please mark it Ready for Review now. The PR is green, clean, and ready to merge; after the Ready transition, please merge it using the repository's configured strategy.

Paulo Aboim Pinto

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants