Skip to content

feat: lock-management surface — unlock + promote (#391) - #395

Merged
robotrocketscience merged 9 commits into
mainfrom
feat/issue-391-lock-management
May 3, 2026
Merged

robotrocketscience merged 9 commits into
mainfrom
feat/issue-391-lock-management

Conversation

@robotrocketscience

@robotrocketscience robotrocketscience commented May 3, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #391 (Track E of #382). Extends the lock-management surface
with unlock and promote (CLI + MCP), and gives the existing
demote lock-clearing path an audit row for parity.

  • aelf unlock <belief_id> / aelf_unlock MCP tool — pure inverse
    of aelf lock. Clears lock_level / locked_at /
    demotion_pressure; does not touch origin. Idempotent
    (re-unlock of an unlocked belief is a no-op, no audit row).
  • aelf promote <belief_id> / aelf_promote MCP tool — alias of
    aelf validate. Functionally identical; both forms ship for
    surface-discoverability per the issue.
  • demote lock-clearing path now writes a lock:unlock audit row
    (was previously silent). Devalidate path unchanged
    (promotion:revert_to_agent_inferred).
  • New promotion.unlock(store, belief_id, *, source_label, now)
    alongside promote() / devalidate(). Returns UnlockResult.
    Refuses (ValueError) on belief-not-found.

Audit-row inventory after this PR

op source label
aelf lock (re-assert) corroboration row (existing)
aelf unlock / demote-lock-drop lock:unlock (new)
aelf promote / aelf validate promotion:user_validated
demote-devalidate promotion:revert_to_agent_inferred

Test plan

  • tests/test_lock_management.py — 31 tests:
    idempotency, error paths, lock-state machine round-trip
    (lock → unlock → re-lock), CLI parity (unlock
    demote-lock-drop), validatepromote, MCP shape parity.
  • Full suite: 2273 passed, 22 skipped, ~34s. Zero regressions.
  • Discretion grep: clean.

Out of scope

Rollback

git revert <pr-merge-sha> — schema-additive only (new audit row
source label), no migrations, no shipped consumers depend on the
new label yet.

Summary by Sourcery

Extend lock management with explicit unlock and promote operations across CLI, MCP tools, and audit logging, and add comprehensive acceptance tests for the lock state machine.

New Features:

  • Add unlock operation to promotion layer, CLI, MCP tools, and slash commands to drop user locks without changing origin while recording audit events.
  • Introduce promote as a first-class alias of validate in CLI, MCP tools, and slash commands for more discoverable belief promotion.

Enhancements:

  • Route demote’s lock-drop path through the shared unlock helper so it now records a lock:unlock audit row.
  • Expand MCP and CLI documentation to describe the new unlock and promote tools and their behaviors.

Documentation:

  • Document the new aelf:unlock and aelf:promote MCP tools and CLI commands, including response shapes and semantics.

Tests:

  • Add lock management acceptance tests covering unlock idempotency and auditing, demote regression behavior, promote/validate parity, MCP tool shapes, and lock→unlock→re-lock round trips.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added unlock command to remove user-locks from beliefs while preserving their origin tier and audit trail.
    • Added promote command as an alias to validate for promoting agent-inferred beliefs to user-validated status.
    • Added new MCP tools aelf:unlock and aelf:promote for programmatic lock and promotion management.
  • Bug Fixes

    • Updated demote command to properly log unlock operations through audit events.
  • Documentation

    • Added command documentation for unlock and promote.
    • Updated MCP tool specifications and tool count (nine → eleven tools).
  • Tests

    • Added comprehensive test suite for unlock, promote, and demote behavior across CLI and MCP interfaces.

New UnlockResult dataclass and unlock() function. Clears lock_level,
locked_at, and demotion_pressure without touching origin. Idempotent —
re-unlock of a non-locked belief is a no-op (no audit row, returns
already_unlocked=True). Refusal: belief not found → ValueError. Writes
lock:unlock audit row via insert_feedback_event on the active path.
…ity (#391)

Both cli._cmd_demote and tool_demote previously cleared lock fields
inline without writing an audit row. Now both delegate to unlock()
so the lock:unlock event is recorded in feedback_history. Behavior is
otherwise unchanged — demote still prints "demoted:" and returns the
same dict shape.
unlock: explicit lock-drop with lock:unlock audit row. Idempotent —
already-unlocked belief returns exit 0 with "already unlocked:" message.
promote: user-facing alias of validate; routes to the same handler
(_cmd_validate) and accepts the same --source flag. Both subcommands
are visible in help (not hidden like validate/demote).
tool_unlock: pure handler, idempotent. Returns {kind, id, unlocked,
audit_event_id?} on active path; {kind, id, unlocked=False} on
already-unlocked; {kind, id, unlocked=False, error} on not-found.
tool_promote: alias of tool_validate, identical semantics and return
shape. Both registered with @mcp.tool() alongside their peers.
31 tests covering: unlock() idempotency + field clearing + audit row
+ error path; demote lock-drop audit row regression; promote/validate
CLI parity via file-backed stores; tool_unlock + tool_promote MCP
shape parity; lock state machine round-trip (locked → unlocked →
re-locked).
COMMANDS.md: add unlock and promote rows with idempotency and
audit-row callouts; clarify demote delegates to unlock for parity.
MCP.md: bump tool count 9→11, add aelf:unlock + aelf:promote rows
with return-shape columns, expand footer note.
…les (#391)

New slash_commands/unlock.md and promote.md following the existing
format. Register both in tests/test_slash_commands.py EXPECTED_COMMANDS
so the slash/CLI parity test passes.
@coderabbitai

coderabbitai Bot commented May 3, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@robotrocketscience has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 54 minutes and 34 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 809d2d40-b07e-4552-995b-ad711f6d720a

📥 Commits

Reviewing files that changed from the base of the PR and between d2d40d1 and d147a5f.

📒 Files selected for processing (1)
  • docs/MCP.md
📝 Walkthrough

Walkthrough

This PR implements lock-management operations (unlock, promote, demote refactor) across CLI, MCP tools, and core logic. It adds unlock() to clear user-locks without origin changes, promote as a validated alias, and refactors demote to delegate through unlock() for consistent audit logging. Includes comprehensive test coverage and documentation updates.

Changes

Lock Management Surface

Layer / File(s) Summary
Core Logic
src/aelfrice/promotion.py
New unlock() function clears LOCK_USER without modifying origin; returns UnlockResult with already_unlocked idempotency flag. Writes lock:unlock audit row on active path. Adds SOURCE_LOCK_UNLOCK constant.
CLI Command Handlers
src/aelfrice/cli.py
New _cmd_unlock() and _cmd_promote() subcommands; _cmd_demote() refactored to call unlock() instead of mutating lock fields directly. All three wired to build_parser().
MCP Tool Handlers
src/aelfrice/mcp_server.py
New tool_unlock() and tool_promote() with structured result shapes (unlock.not_found, unlock.already, unlock.unlocked); tool_demote() refactored to call unlock(). Both registered in serve() via FastMCP decorators.
Operator Documentation
docs/COMMANDS.md
Documented unlock <belief_id> (user-lock drop, idempotent) and promote <belief_id> (alias of validate). Updated demote description to reflect delegation through unlock().
MCP Contract Documentation
docs/MCP.md
Tool count updated from nine to eleven. Tools table expanded with aelf:unlock, aelf:promote, aelf:validate, aelf:health rows; return shapes include prior_origin, new_origin, audit_event_id?. Narrative clarifies unlock semantics and promote as validate alias.
Slash Command Metadata
src/aelfrice/slash_commands/unlock.md, src/aelfrice/slash_commands/promote.md
New command files defining execution (uv run aelf unlock/promote), idempotency, and behavior (lock drop preserves origin; promote is alias of validate).
Test Coverage
tests/test_lock_management.py, tests/test_slash_commands.py
31 new test functions validating unlock idempotency, audit row generation, error paths, demote delegation, CLI/MCP parity, lock state-machine round-trips, and promote/validate alignment. Updated EXPECTED_COMMANDS to include unlock and promote.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

author-Setr

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 29.09% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed Title clearly summarizes the main change: adding lock-management surface (unlock and promote commands) to the codebase.
Description check ✅ Passed Description is comprehensive, covering summary, linked issues, type of change (marked), verification steps, test plan, and notes. All required template sections are present and filled.
Linked Issues check ✅ Passed PR fully addresses #391 requirements: unlock and promote CLI/MCP tools, audit logging, idempotency testing, error paths covered, documentation updated, demote audit parity achieved.
Out of Scope Changes check ✅ Passed All changes are within scope of #391: new unlock/promote functionality, demote lock-drop audit logging, supporting tests and documentation. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-391-lock-management

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
Review rate limit: 0/1 reviews remaining, refill in 54 minutes and 34 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai

sourcery-ai Bot commented May 3, 2026

Copy link
Copy Markdown

Reviewer's Guide

Extends the lock-management surface by introducing a shared unlock primitive (with audit logging) and a promote alias, wiring them through CLI, MCP tools, docs, and tests, while refactoring demote to use the new unlock path for consistent behavior and audit coverage.

Sequence diagram for CLI unlock and demote lock-drop using shared unlock primitive

sequenceDiagram
  actor User
  participant CLI_unlock_cmd as CLI _cmd_unlock
  participant CLI_demote_cmd as CLI _cmd_demote
  participant Promotion_unlock as promotion.unlock
  participant MemoryStore as MemoryStore
  participant FeedbackStore as feedback_history

  User->>CLI_unlock_cmd: run aelf unlock belief_id
  CLI_unlock_cmd->>MemoryStore: _open_store()
  activate MemoryStore
  CLI_unlock_cmd->>Promotion_unlock: unlock(store, belief_id)
  alt belief_not_found
    Promotion_unlock->>MemoryStore: get_belief(belief_id) -> None
    Promotion_unlock-->>CLI_unlock_cmd: raise ValueError
    CLI_unlock_cmd-->>User: stderr "belief not found" (exit 1)
  else already_unlocked
    Promotion_unlock->>MemoryStore: get_belief(belief_id) -> belief(lock_level != LOCK_USER)
    Promotion_unlock-->>CLI_unlock_cmd: UnlockResult(already_unlocked=True, audit_event_id=None)
    CLI_unlock_cmd-->>User: stdout "already unlocked" (exit 0)
  else active_unlock
    Promotion_unlock->>MemoryStore: get_belief(belief_id) -> belief(lock_level == LOCK_USER)
    Promotion_unlock->>MemoryStore: update_belief(cleared lock_level, locked_at, demotion_pressure)
    Promotion_unlock->>FeedbackStore: insert_feedback_event(source=SOURCE_LOCK_UNLOCK, valence=0.0)
    FeedbackStore-->>Promotion_unlock: audit_event_id
    Promotion_unlock-->>CLI_unlock_cmd: UnlockResult(already_unlocked=False, audit_event_id)
    CLI_unlock_cmd-->>User: stdout "unlocked" (exit 0)
  end
  CLI_unlock_cmd->>MemoryStore: close()
  deactivate MemoryStore

  User->>CLI_demote_cmd: run aelf demote belief_id
  CLI_demote_cmd->>MemoryStore: _open_store()
  activate MemoryStore
  CLI_demote_cmd->>MemoryStore: get_belief(belief_id)
  alt lock_level == LOCK_USER
    CLI_demote_cmd->>Promotion_unlock: unlock(store, belief_id)
    Promotion_unlock-->>CLI_demote_cmd: UnlockResult(...)
    CLI_demote_cmd-->>User: stdout "demoted" (lock tier only)
  else origin == ORIGIN_USER_VALIDATED
    CLI_demote_cmd->>Promotion_unlock: devalidate(store, belief_id)
    CLI_demote_cmd-->>User: stdout "demoted" (origin tier)
  else
    CLI_demote_cmd-->>User: stdout "no-op demote" (already lowest tier)
  end
  CLI_demote_cmd->>MemoryStore: close()
  deactivate MemoryStore
Loading

Sequence diagram for MCP aelf_unlock and aelf_promote tools

sequenceDiagram
  actor Agent
  participant MCP as MCP_server
  participant Tool_unlock as tool_unlock
  participant Tool_promote as tool_promote
  participant Promotion_unlock as promotion.unlock
  participant Tool_validate as tool_validate
  participant MemoryStore as MemoryStore

  Agent->>MCP: call aelf_unlock(belief_id)
  MCP->>Tool_unlock: tool_unlock(store, belief_id)
  Tool_unlock->>Promotion_unlock: unlock(store, belief_id)
  alt belief_not_found
    Promotion_unlock-->>Tool_unlock: raise ValueError
    Tool_unlock-->>Agent: {kind: unlock.not_found, id, unlocked: false, error}
  else already_unlocked
    Promotion_unlock-->>Tool_unlock: UnlockResult(already_unlocked=True, audit_event_id=None)
    Tool_unlock-->>Agent: {kind: unlock.already, id, unlocked: false}
  else unlocked
    Promotion_unlock-->>Tool_unlock: UnlockResult(already_unlocked=False, audit_event_id)
    Tool_unlock-->>Agent: {kind: unlock.unlocked, id, unlocked: true, audit_event_id}
  end

  Agent->>MCP: call aelf_promote(belief_id, source)
  MCP->>Tool_promote: tool_promote(store, belief_id, source)
  Tool_promote->>Tool_validate: tool_validate(store, belief_id, source)
  Tool_validate-->>Agent: {kind, id, prior_origin, new_origin, audit_event_id?}
Loading

Class diagram for promotion results and unlock primitive

classDiagram
  class PromotionResult {
    +str belief_id
    +str prior_origin
    +str new_origin
    +int audit_event_id
    +bool already_validated
  }

  class UnlockResult {
    +str belief_id
    +bool already_unlocked
    +int audit_event_id
  }

  class PromotionModule {
    +promote(store, belief_id, source_label, now) PromotionResult
    +devalidate(store, belief_id, source_label, now) PromotionResult
    +unlock(store, belief_id, source_label, now) UnlockResult
  }

  class MemoryStore {
    +get_belief(belief_id) Belief
    +update_belief(belief)
    +insert_feedback_event(belief_id, valence, source, created_at) int
  }

  class Belief {
    +str id
    +int lock_level
    +str origin
    +str locked_at
    +int demotion_pressure
  }

  class Constants {
    +int LOCK_NONE
    +int LOCK_USER
    +str SOURCE_PROMOTION_USER_VALIDATED
    +str SOURCE_REVERT_TO_AGENT_INFERRED
    +str SOURCE_LOCK_UNLOCK
  }

  PromotionModule ..> UnlockResult : returns
  PromotionModule ..> PromotionResult : returns
  PromotionModule ..> MemoryStore : uses
  MemoryStore o--> Belief : stores
  PromotionModule ..> Constants : uses constants
Loading

File-Level Changes

Change Details Files
Introduce unlock() domain primitive that clears user locks, is idempotent, and writes a lock:unlock audit row, plus a corresponding UnlockResult type and audit source label.
  • Add SOURCE_LOCK_UNLOCK audit source label for lock-unlock events.
  • Define UnlockResult dataclass capturing belief_id, already_unlocked, and optional audit_event_id.
  • Implement unlock(store, belief_id, source_label, now) to clear lock fields, keep origin and alpha/beta intact, be idempotent on already-unlocked beliefs, and write a zero-valence feedback event on the active path.
  • Make unlock raise ValueError when the belief does not exist.
src/aelfrice/promotion.py
Refactor demote lock-clearing logic to delegate to unlock(), ensuring audit coverage and consistent behavior across MCP and CLI.
  • Update MCP tool_demote to call promotion.unlock() when clearing a user lock instead of manually mutating the belief.
  • Update CLI _cmd_demote to delegate its lock-drop branch to promotion.unlock() instead of inlining field resets.
  • Verify that demote still clears lock_level and now emits a lock:unlock audit row via unlock().
src/aelfrice/mcp_server.py
src/aelfrice/cli.py
tests/test_lock_management.py
Expose unlock as a first-class operation over MCP and CLI, including tool wrappers, commands, and slash-command metadata.
  • Add tool_unlock in the MCP server that wraps promotion.unlock(), normalizing not-found, already-unlocked, and active-path responses into structured result shapes.
  • Register the aelf_unlock MCP tool and include it in the MCP tool registry.
  • Add CLI _cmd_unlock handler that calls promotion.unlock(), prints user-facing messages for success/already-unlocked/not-found, and returns appropriate exit codes.
  • Wire an unlock subcommand into the CLI parser with belief_id argument and help text.
  • Add slash-command spec for aelf:unlock that runs uv run aelf unlock and describes semantics and idempotency.
  • Document aelf:unlock in MCP and COMMANDS docs, including response shape and audit behavior.
src/aelfrice/mcp_server.py
src/aelfrice/cli.py
src/aelfrice/slash_commands/unlock.md
docs/MCP.md
docs/COMMANDS.md
tests/test_slash_commands.py
tests/test_lock_management.py
Introduce promote as a user-facing alias of validate across MCP, CLI, and slash commands, ensuring identical semantics, audit behavior, and result shapes.
  • Add tool_promote in the MCP server that forwards to tool_validate while preserving the source parameter and result shape.
  • Register the aelf_promote MCP tool and include it in the MCP tool registry.
  • Add CLI _cmd_promote function that simply calls _cmd_validate for shared behavior.
  • Wire a promote subcommand into the CLI parser that mirrors validate flags (belief_id and --source) and delegates to _cmd_promote.
  • Add slash-command spec for aelf:promote that runs uv run aelf promote with documented semantics and idempotency.
  • Update MCP docs to list aelf:promote, clarify that it is an alias of validate, and adjust validate’s documented response shape to include prior/new origin and audit_event_id.
  • Update COMMANDS docs and slash command tests to include the new promote command and ensure it appears in the slash-commands list.
src/aelfrice/mcp_server.py
src/aelfrice/cli.py
src/aelfrice/slash_commands/promote.md
docs/MCP.md
docs/COMMANDS.md
tests/test_slash_commands.py
tests/test_lock_management.py
Add comprehensive tests for lock-management behavior, covering unlock semantics, demote regression, promote/validate parity, MCP tool shapes, and lock round-trips.
  • Introduce tests/test_lock_management.py with helpers for seeding beliefs and constructing locked beliefs.
  • Test unlock()’s field clearing, origin and alpha/beta invariants, idempotency (including never-locked beliefs), error handling on missing beliefs, and audit-row content (source, valence, belief_id, timestamp, audit_event_id).
  • Verify that demote’s lock-drop path now writes a lock:unlock audit row while preserving its demoted response shape and clearing lock_level.
  • Exercise CLI promote vs validate parity using file-backed MemoryStore instances and environment overrides, asserting identical origin changes and audit sources.
  • Check MCP tool_unlock and tool_promote response shapes and parity with tool_validate, including idempotent paths and origin changes.
  • Validate the lock state machine round-trip (lock → unlock → re-lock → unlock) including audit trail expectations and lock-level transitions.
tests/test_lock_management.py

Assessment against linked issues

Issue Objective Addressed Explanation
#391 Implement unlock and promote lock-management operations (core logic) and expose them via CLI and MCP, with demote using the same lock-clearing path and writing appropriate audit-log entries.
#391 Add tests covering idempotency, error paths, and lock-state machine transitions for unlock / promote / demote across CLI and MCP surfaces.
#391 Document the new unlock and promote surfaces and behaviors in MCP and CLI documentation (including COMMANDS.md, MCP.md, and related slash-command docs).

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@sourcery-ai sourcery-ai 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.

Hey - I've left some high level feedback:

  • The MCP docs now describe aelf:validate/aelf:promote as returning {prior_origin, new_origin, audit_event_id?}, but the existing tool_validate implementation still appears to return a single origin field; consider updating either the implementation or the docs so the response shape matches exactly.
  • When tool_demote follows the lock-drop path it now delegates to unlock() but discards the audit_event_id; if consumers might care about the audit row for symmetry with tool_unlock, consider including that ID in the demote.demoted response.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The MCP docs now describe `aelf:validate`/`aelf:promote` as returning `{prior_origin, new_origin, audit_event_id?}`, but the existing `tool_validate` implementation still appears to return a single `origin` field; consider updating either the implementation or the docs so the response shape matches exactly.
- When `tool_demote` follows the lock-drop path it now delegates to `unlock()` but discards the `audit_event_id`; if consumers might care about the audit row for symmetry with `tool_unlock`, consider including that ID in the `demote.demoted` response.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread tests/test_lock_management.py Fixed
@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:Toug:2026-05-03T20:51:10Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:Setr:2026-05-03T20:51:38Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:Setr:2026-05-03T20:51:43Z]

@robotrocketscience
robotrocketscience enabled auto-merge (rebase) May 3, 2026 20:55
auto-merge was automatically disabled May 3, 2026 20:56

Branch protection rule check failed

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/MCP.md`:
- Around line 39-40: Update the MCP docs table entries for the `aelf:validate`
and `aelf:promote` return shapes to be a union that explicitly includes both the
success object `{kind, id, prior_origin, new_origin, audit_event_id?}` and the
error variant `{kind: "validate.error", error}`; mention that the error variant
is returned on invalid requests so clients can parse the union safely for
`aelf:validate` and `aelf:promote`.
- Line 45: Update the wording for the aelf:unlock description so it no longer
claims it “always writes” a lock:unlock audit row; change the phrase to indicate
that a lock:unlock audit row is written only when a lock is actually removed
(i.e., not in the already-unlocked idempotent path). Reference the existing term
"aelf:unlock" and the audit row name "lock:unlock" when making this single-line
edit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fb088468-c9e3-401b-ba97-00266951bbec

📥 Commits

Reviewing files that changed from the base of the PR and between 2674337 and d2d40d1.

📒 Files selected for processing (9)
  • docs/COMMANDS.md
  • docs/MCP.md
  • src/aelfrice/cli.py
  • src/aelfrice/mcp_server.py
  • src/aelfrice/promotion.py
  • src/aelfrice/slash_commands/promote.md
  • src/aelfrice/slash_commands/unlock.md
  • tests/test_lock_management.py
  • tests/test_slash_commands.py

Comment thread docs/MCP.md Outdated
Comment thread docs/MCP.md Outdated
@robotrocketscience
robotrocketscience enabled auto-merge (rebase) May 3, 2026 21:00
auto-merge was automatically disabled May 3, 2026 21:01

Branch protection rule check failed

@robotrocketscience
robotrocketscience merged commit d147a5f into main May 3, 2026
18 checks passed
@robotrocketscience
robotrocketscience deleted the feat/issue-391-lock-management branch May 3, 2026 21:07
@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:Toug:2026-05-03T21:07:28Z]

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

Labels

attn:review Needs review (PR open, awaiting reviewer)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v2.0 / Track E] unlock / promote / demote lock-management surface (CLI + MCP)

2 participants