release(v4.8.4): bump framework and eight skills to 4.8.4 in lockstep; archive PR #47 reviews (two rounds)
The .claude/skills check accepts both local layouts and fails on a dangling link. Review: round 1 (@e1ed270) claude agy grok PASS, codex NOT PASS (a dangling top-level link was skipped); fixed in 150b493; round 2 4/4 PASS. Reports and the round-2 identity sidecars go to .agents/reports/<session>/. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VCgu9Fa9iT7TbJUSzdq4Ff
This commit is contained in:
1 parent
150b4937f8
commit
65dc7fde82
28 files changed
+543
-25
No files matched your search
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"loop_id": "loop-20261004T044643Z-1b1440",
|
||||
"base_sha": "e1ed2708d835d712f5f3a9dfd51b8f66ca1ac447",
|
||||
"head_sha": "150b4937f816c6407be16fc4c37ab88e478927e7",
|
||||
"tree_sha": "afce44d2e0f91720d81e8d7d484f0e1358dee680",
|
||||
"review_commit": "150b4937f816c6407be16fc4c37ab88e478927e7",
|
||||
"reviewer": "reviewer-grok-01",
|
||||
"job_id": "0b77d5de",
|
||||
"verdict": "PASS",
|
||||
"transport": "herdr",
|
||||
"evidence": "review-tree",
|
||||
"isolation": "worktree",
|
||||
"verified_at": "2026-10-04T04:54:16Z"
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# Review: PR #47 round 2 @ 150b493
|
||||
|
||||
- Role: Reviewer (grok)
|
||||
- Identity: base `e1ed2708d835d712f5f3a9dfd51b8f66ca1ac447`, head `150b4937f816c6407be16fc4c37ab88e478927e7`, tree `afce44d2e0f91720d81e8d7d484f0e1358dee680`, 1 commit, clean worktree
|
||||
- Verified read-only at `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261004T044643Z-1b1440/1`, except temporary `.claude/skills` layouts created there and removed afterward. Main stayed at `6af4a79`. The control-plane `.claude/skills` was only read.
|
||||
- `git diff --stat e1ed270..HEAD`: `tests/test_issue42_skill_blocks.py`, +59/−12. `git diff --check` is clean. No product file and no version line.
|
||||
|
||||
Round 1 on `e1ed270` was PASS from this reviewer. The report noted that a dangling `.claude/skills` symlink skipped, because `Path.exists()` follows the link and is false before `is_symlink()` was considered. Codex R1 is that note. This commit closes it.
|
||||
|
||||
| Round 1 | `150b493` |
|
||||
|---|---|
|
||||
| `exists()` false meant skip, including a dangling top-level symlink | Absence is `not exists() and not is_symlink()` (`tests/test_issue42_skill_blocks.py:248-249`). A symlink is then checked (`250-252`): it must exist and resolve to `.agents/skills`, otherwise the function returns a problem. |
|
||||
| The live test skipped in a worktree, so the dangling case never ran | `test_claude_skills_layouts` builds six layouts under `tmp_path` and calls the same function (`294`). `broken_top` expects a non-empty problem list (`282-283`, `299-300`). `None` (the old skip) and `[]` both fail that assertion. |
|
||||
|
||||
## Same function, deterministic layouts
|
||||
|
||||
`claude_skills_problems` (`240-260`) is the only checker. The live test calls it with `REPO / ".claude" / "skills"`, `SKILLS`, and `SKILL_NAMES` (`263-267`). The synthetic test calls it with the temp link, the temp skills directory, and two fixed names (`274-275`, `294`). Success layouts assert `problems == []`. The absent layout asserts `None`. The three failure layouts assert the list is non-empty. They do not pin the message text. The live test does: a present layout must be exactly `[]`.
|
||||
|
||||
The six layouts are built with relative links inside `tmp_path` (`../.agents/skills`, `../../.agents/skills/<name>`). Nothing in the repo tree is required, so the cases run in a worktree. `broken_top` points at `../.agents/no-such-dir`. `broken_entry` replaces the second skill with a link to `gone`. `wrong_skill` points `multi-agent-mux-b` at `multi-agent-mux-a`.
|
||||
|
||||
## Probes
|
||||
|
||||
Temporary layouts in the snapshot, then removed (`git status` clean, `.claude` gone):
|
||||
|
||||
- No `.claude/skills`: `37 passed, 1 skipped in 0.07s`. The skip is the live test. The six synthetic layouts are among the 37.
|
||||
- Dangling `ln -s ../.agents/skills-missing .claude/skills`: the live test failed at `:267` with a non-empty problem list. It did not skip. `Path.resolve()` on that dangling link returned the missing path and did not raise.
|
||||
- Directory of the eight skill links plus `lib.sh` and `lib_py`: the live test passed.
|
||||
|
||||
The control-plane directory is not a symlink. `claude_skills_problems` on that path, the control-plane `.agents/skills`, and this tree's eight `SKILL_NAMES` returned `[]`.
|
||||
|
||||
[VERDICT: PASS]
|
||||
@@ -0,0 +1,47 @@
|
||||
# Review: PR #47 @ e1ed270
|
||||
|
||||
- Role: Reviewer (grok)
|
||||
- Identity: base `6af4a796b1bdce3b2e929b7a45a8a22d66b36855`, head `e1ed2708d835d712f5f3a9dfd51b8f66ca1ac447`, tree `2f781e0db4df9a3082b4f55e69c42118868b18a1`, 1 commit, clean worktree
|
||||
- Verified read-only at `/var/folders/q_/68sxgw3j073dgjg8wl9s08vw0000gn/T/mam-review/loop-20261004T043243Z-baf133/1`, except temporary `.claude/skills` layouts created there and removed afterward. Main stayed at `6af4a79`. The control-plane `.claude/skills` was only read.
|
||||
- `git diff --stat 6af4a79..HEAD`: `tests/test_issue42_skill_blocks.py`, +10/−1. `git diff --check` is clean. No product file and no version line.
|
||||
|
||||
`.claude/` is gitignored (`.gitignore:40`). This checkout's `.claude/skills` is a real directory, not one symlink. It holds the eight `multi-agent-mux-*` links plus `lib.sh` and `lib_py`, each aimed at `../../.agents/skills/<name>`. The old assertion `link.resolve() == SKILLS.resolve()` fails that directory. A worktree has no `.claude/skills`, so the same test skipped during the PR #46 runs.
|
||||
|
||||
## The two layouts
|
||||
|
||||
`test_claude_skills_link_resolves_to_agents_skills` (`tests/test_issue42_skill_blocks.py:240-253`):
|
||||
|
||||
- Missing path: skip (`245-246`). A worktree stays green.
|
||||
- The path is a symlink: it must resolve to `.agents/skills` (`247-249`). Children are not checked, because they are the repo skills.
|
||||
- Otherwise each name from `SKILL_NAMES` (`:22`, the eight `multi-agent-mux-*/SKILL.md` directories) must exist under `.claude/skills` and resolve to `.agents/skills/<skill>` (`250-253`).
|
||||
|
||||
Temporary layouts in the snapshot, deleted before the end (`git status` clean, `.claude` gone):
|
||||
|
||||
| Layout | Result |
|
||||
|---|---|
|
||||
| absent | skipped |
|
||||
| symlink `../.agents/skills` | passed |
|
||||
| symlink to `multi-agent-mux-create` only | failed at `:248` (create's path `!=` `.agents/skills`) |
|
||||
| directory of the eight links, plus `lib.sh` and `lib_py` | full file **32 passed** |
|
||||
| `multi-agent-mux-stop` linked at `multi-agent-mux-create` | failed at `:253`, and the message shows the create path |
|
||||
| `multi-agent-mux-resume` linked at a missing target | failed at `:252` (`is missing`) |
|
||||
| `.claude/skills` a regular file | failed at `:252` (`multi-agent-mux-create is missing`) |
|
||||
|
||||
The control-plane links resolve to the same comparison: `multi-agent-mux-create` there equals `.agents/skills/multi-agent-mux-create`. Pytest was not run in that checkout.
|
||||
|
||||
## Edges
|
||||
|
||||
- A regular file is not accepted. `is_symlink()` is false, then `link / skill` does not exist, so the test fails.
|
||||
- `lib.sh` and `lib_py` beside the eight links do not fail the test. Neither has a `SKILL.md` (`lib.sh` is a file; `lib_py` is the package). Claude Code loads a skill from a directory that contains `SKILL.md`. Those two entries are not skills, and this checkout has them, so rejecting every extra name would be too strict. The test's job is the eight repo skills. An extra untracked directory that did contain its own `SKILL.md` would not be looked at; that is a local skill outside this check.
|
||||
- A broken per-skill link fails `entry.exists()` (`:252`). `exists()` follows the link, so a dangling symlink is "missing" and the test fails.
|
||||
- A broken symlink at `.claude/skills` itself is skipped. `Path.exists()` is false for a dangling symlink, and that check runs before `is_symlink()` (`245-247`). The previous test skipped the same way. Claude Code would not load skills through that link either. A present-but-wrong root symlink, one whose target exists, still fails the resolve check.
|
||||
- An empty `SKILL_NAMES` would make the directory branch pass without checking any entry. The name list is the eight `SKILL.md` parents, and `test_inventory_covers_eight_skills` in the same file requires eight skills. The directory branch is not empty on this tree.
|
||||
|
||||
## Checks
|
||||
|
||||
Snapshot, control-plane venv, `--basetemp` under `/tmp/adb45follow.*` (removed after each run):
|
||||
|
||||
- No `.claude/skills`: `31 passed, 1 skipped in 0.06s`. The skip is this test.
|
||||
- The per-skill directory with `lib.sh` and `lib_py`: `32 passed in 0.06s`.
|
||||
|
||||
[VERDICT: PASS]
|
||||
Reference in new issue
Block a user