Skip to content

test: backfill 409 conflict-path fixture for Phase B (Commands) sync route #772

@memtomem

Description

@memtomem

Background

ADR-0001 §5 c4 ("conflict path covered by a test fixture") requires
either an HTTP 409 fixture (Skills' optimistic-locking design) or a
documented soft-abort response. Phase B (Commands) shipped before §5
was authored (RFC #761 / ADR landed in #769) and lacks an HTTP-layer
stale-mtime 409 fixture parallel to Skills and Agents.

Per ADR-0001 §5: "§5 applies to future phase promotions. It does
not retroactively fail Phases A–C — those shipped under earlier
review and gaps … are tracked as hygiene follow-ups, not regressions."

This is the hygiene follow-up for Phase B. (The Phase C sibling
#773 was closed as already-covered — Agents has the test at
tests/test_web_routes_context.py:772.)

Current 409 coverage map

Phase Stale-mtime 409 fixture Concurrent PUT race 409
A Skills test_web_routes_context.py:224 (TestUpdateSkill.test_mtime_conflict) ✓ via TYPE_MATRIX at test_web_routes_context_mutators.py:405
B Commands MISSING — this issue ✓ via TYPE_MATRIX
C Agents test_web_routes_context.py:772 (TestAgentCRUD.test_mtime_conflict_after_external_write) ✓ via TYPE_MATRIX

The concurrent-PUT race test at mutators.py:405 is a different
shape
— two parallel PUTs serialize under the in-process lock and
the second 409s. The §5 c4 fixture this issue tracks is the
stale-mtime flavor: a single PUT with a mtime_ns from before
an external write to the runtime file, mirroring Skills' and Agents'
existing patterns.

Scope

Add one new test method to TestCommandCRUD in
packages/memtomem/tests/test_web_routes_context.py (the class at
line 552, between test_create_update_delete at line 554 and
TestSyncCommands at line 579). Mirror the Agents pattern verbatim
— the PUT body shape ({"content": "...", "mtime_ns": "..."}) and
the assertion set (HTTP 409, status: "aborted", mtime_ns echo,
file-content-unchanged check) are identical between Skills/Agents,
so the diff is mostly fixture-setup substitution.

Helper picker:

  • Use _make_command (already defined at
    test_web_routes_context.py:454) instead of _make_skill or
    _make_agent. Commands are single-file artifacts (<name>.md),
    not folders.
  • Sync via POST /api/context/commands/sync (matches the existing
    pattern at :779 for Agents).
  • Target path: tmp_path / ".claude" / "commands" / "<name>.md".

The PUT body / assertion section can be copied byte-for-byte from
the Agents test at :791-802, with the URL changed from
/api/context/agents/<name> to /api/context/commands/<name> and
the content shape changed from agent frontmatter to command
frontmatter.

The 409 path itself already exists in production code at
packages/memtomem/src/memtomem/web/routes/context_commands.py:241-250
(current_mtime_ns != body_mtime_ns → 409 + status: "aborted",
verbatim identical to the Skills handler at
context_skills.py:199-208). This issue is purely test-coverage
backfill.

Acceptance

  • One new test in TestCommandCRUD
    (test_web_routes_context.py) exercises the stale-mtime 409
    path via PUT /api/context/commands/<name>.
  • Test shape matches the Agents counterpart at line 772
    (canonical sync → external os.utime bump → stale-mtime PUT
    → assert HTTP 409 + status: "aborted" + mtime_ns echo +
    content-unchanged).
  • uv run pytest -m "not ollama" tests/test_web_routes_context.py
    green.

Out of scope

  • Implementation changes to Commands sync routes — the 409 path
    already exists in production code. This issue is purely
    test-coverage backfill.
  • Phase A / C — already covered (see map above).

Refs: #761 (parent RFC, closed); #773 (Phase C sibling, closed as
already-covered).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions