Skip to content

test(context-gateway): tighten Skills mtime-conflict to pin §5 c4 no-write semantics (closes #778)#779

Merged
memtomem merged 1 commit intomainfrom
fix/issue-778-skills-mtime-conflict-tighten
May 4, 2026
Merged

test(context-gateway): tighten Skills mtime-conflict to pin §5 c4 no-write semantics (closes #778)#779
memtomem merged 1 commit intomainfrom
fix/issue-778-skills-mtime-conflict-tighten

Conversation

@memtomem
Copy link
Copy Markdown
Owner

@memtomem memtomem commented May 4, 2026

Summary

What §5 c4 actually requires

§5 c4 pins conflict semantics, not just the response label. The
existing TestUpdateSkill.test_mtime_conflict (status_code == 409 +
status == "aborted") would still pass a regression that wrote
body.content and then returned the abort envelope.

This PR adds two assertions on top of the existing pair:

  1. data["mtime_ns"] == str(manifest_path.stat().st_mtime_ns) — pins the retry-hint contract from context_skills.py:199-208.
  2. manifest_path.read_text(...) == "# Test skill\n" — pins the no-write semantics §5 c4 actually targets.

Mutation validation

Before commit, I verified the hardened test is regression-tight by
mutating context_skills.py:198-209 to perform atomic_write_text
before the mtime-guard. The 409 / status == "aborted" / mtime_ns
echo assertions all still passed (the response shape is unchanged),
but the new content assertion failed on '# Changed' == '# Test skill'
— confirming the test catches exactly the class of regression §5 c4 is
designed to prevent. The mutation was reverted before the commit
(git diff packages/memtomem/src/memtomem/web/routes/context_skills.py
returns empty in the final commit).

Phase strictness map (post-merge)

Phase status: "aborted" no-write content mtime_ns echo
A Skills (this PR) ✓ (new) ✓ (new)
B Commands (PR #777)
C Agents

The Phase B mtime_ns echo gap is intentionally out of scope here —
§5 c4's "conflict semantics" requirement is satisfied by the no-write
assertion alone, which #777 already pins. File a separate hygiene
issue if the team wants strict three-phase echo parity.

Test plan

  • uv run pytest -m "not ollama" packages/memtomem/tests/test_web_routes_context.py — 57/57 green
  • uv run ruff check packages/memtomem/tests/test_web_routes_context.py
  • uv run ruff format --check packages/memtomem/tests/test_web_routes_context.py
  • Mutation test (write-before-guard) → assertion fail confirmed → mutation reverted

Refs: #778, #777 (Phase B sibling), #761 (parent RFC), #769 (ADR §5)

🤖 Generated with Claude Code

…write semantics (closes #778)

Phase A (Skills) was the oldest of the three context-gateway phase
tests and only asserted the 409 response label. ADR-0001 §5 c4 pins
**conflict semantics** — a regression that returned 409 + status ==
"aborted" and *then* wrote body.content would have gone undetected.

Tighten ``TestUpdateSkill.test_mtime_conflict`` in place with two
additional assertions, mirroring the strict shape of the Agents test
at ``test_web_routes_context.py:801-802``:

1. ``data["mtime_ns"]`` echoes the manifest's on-disk ``st_mtime_ns``
   — pins the retry-hint contract from ``context_skills.py:199-208``.
2. The manifest content on disk is unchanged after the 409 — pins the
   no-write semantics §5 c4 actually targets.

Verified: mutation-tested by moving ``atomic_write_text`` above the
guard in ``context_skills.py:198-209``; the new content assertion
failed on ``'# Changed' == '# Test skill'`` while the 409 / status /
mtime_ns echo assertions all still passed, confirming the test catches
exactly the class of regression §5 c4 is designed to prevent. The
mutation was reverted before the commit.

The 409 path itself in production code is unchanged — this is purely
test-coverage hardening.

Refs: #778, #777 (Phase B sibling), #761 (parent RFC), #769 (ADR §5)

Co-Authored-By: Claude <[email protected]>
@memtomem memtomem merged commit fe23ab0 into main May 4, 2026
11 checks passed
@memtomem memtomem deleted the fix/issue-778-skills-mtime-conflict-tighten branch May 4, 2026 21:27
@github-actions github-actions Bot locked and limited conversation to collaborators May 4, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

test(skills): tighten TestUpdateSkill.test_mtime_conflict to pin §5 c4 no-write semantics

2 participants