fix(skill): resolve skill add persistence regression after PR #640 #1120

Merged
freemo merged 2 commits from bugfix/m3-skill-add-regression into master 2026-03-24 17:23:10 +00:00
Owner

Summary

Fixes the cross-process skill persistence regression reported in #980. Skills registered via agents skill add --config <file> in one CLI process are now correctly persisted to the database and visible in subsequent CLI invocations.

Root Cause

Two issues in the skill persistence layer:

  1. Missing table creation: _build_skill_service() in container.py created a SkillRepository pointing at the database but did not ensure the skills and skill_items tables existed. When the tables were missing, all repository operations failed silently (caught by SkillService._load_from_db and _persist_skill exception handlers), causing the service to operate in in-memory-only mode.

  2. Session mismatch: SkillRepository lacked auto_commit support. Each call to session_factory() returned a new session, so the flush() in create()/update()/delete() operated on a different session than the commit() in SkillService._commit(), meaning data was never actually persisted.

Fix

  1. Add targeted table creation in _build_skill_service (following the pattern in _build_session_service) — checks for missing skills and skill_items tables and creates them via Base.metadata.create_all.
  2. Add auto_commit parameter to SkillRepository (following the pattern in SessionRepository) so each mutating method commits and closes its own session.
  3. Pass auto_commit=True from the container builder.
  4. Remove @tdd_expected_fail from TDD test (leaving @tdd_bug and @tdd_bug_980 as permanent regression guards).

Quality Gates

  • nox -e lint — passed
  • nox -e typecheck — 0 errors
  • nox -e unit_tests — 462 features, 12232 scenarios passed
  • nox -e integration_tests — 1674 tests, 1674 passed, 0 failed
  • nox -e coverage_report — 98% coverage (threshold: 97%)

Note: This PR depends on PR #1110 (TDD test for #981) being merged first.

Closes #980

## Summary Fixes the cross-process skill persistence regression reported in #980. Skills registered via `agents skill add --config <file>` in one CLI process are now correctly persisted to the database and visible in subsequent CLI invocations. ### Root Cause Two issues in the skill persistence layer: 1. **Missing table creation**: `_build_skill_service()` in `container.py` created a `SkillRepository` pointing at the database but did not ensure the `skills` and `skill_items` tables existed. When the tables were missing, all repository operations failed silently (caught by `SkillService._load_from_db` and `_persist_skill` exception handlers), causing the service to operate in in-memory-only mode. 2. **Session mismatch**: `SkillRepository` lacked `auto_commit` support. Each call to `session_factory()` returned a new session, so the `flush()` in `create()`/`update()`/`delete()` operated on a different session than the `commit()` in `SkillService._commit()`, meaning data was never actually persisted. ### Fix 1. Add targeted table creation in `_build_skill_service` (following the pattern in `_build_session_service`) — checks for missing `skills` and `skill_items` tables and creates them via `Base.metadata.create_all`. 2. Add `auto_commit` parameter to `SkillRepository` (following the pattern in `SessionRepository`) so each mutating method commits and closes its own session. 3. Pass `auto_commit=True` from the container builder. 4. Remove `@tdd_expected_fail` from TDD test (leaving `@tdd_bug` and `@tdd_bug_980` as permanent regression guards). ### Quality Gates - ✅ `nox -e lint` — passed - ✅ `nox -e typecheck` — 0 errors - ✅ `nox -e unit_tests` — 462 features, 12232 scenarios passed - ✅ `nox -e integration_tests` — 1674 tests, 1674 passed, 0 failed - ✅ `nox -e coverage_report` — 98% coverage (threshold: 97%) **Note**: This PR depends on PR #1110 (TDD test for #981) being merged first. Closes #980
freemo added this to the v3.2.0 milestone 2026-03-23 02:39:42 +00:00
test: add TDD bug-capture test for #980 — skill add cross-process persistence
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 3m20s
CI / build (pull_request) Successful in 34s
CI / typecheck (pull_request) Successful in 4m2s
CI / quality (pull_request) Successful in 4m1s
CI / integration_tests (pull_request) Successful in 9m7s
CI / unit_tests (pull_request) Successful in 9m17s
CI / e2e_tests (pull_request) Failing after 11m42s
CI / security (pull_request) Failing after 13m26s
CI / coverage (pull_request) Successful in 12m26s
CI / docker (pull_request) Has been skipped
CI / status-check (pull_request) Failing after 1s
CI / benchmark-regression (pull_request) Successful in 56m8s
7fdbf5d4c6
Write cross-process Behave and Robot tests capturing skill add
persistence regression. Tests use subprocess invocations to verify
skills persist across CLI process boundaries.

The existing persistence tests (skill_add_persist.feature) verify
round-trip within the same Python process by creating two SkillService
instances sharing the same in-memory database. This approach cannot
detect the cross-process regression where _build_skill_service falls
back to in-memory storage because the skills table does not exist in
the database created by agents init.

Behave: features/tdd_skill_add_regression.feature
Robot:  robot/tdd_skill_add_regression.robot

Tags: @tdd_bug, @tdd_bug_980, @tdd_expected_fail

ISSUES CLOSED: #981
freemo left a comment

Day 43 Review — PR #1120 fix(skill): resolve skill add persistence regression

Verdict: Review complete — meets all standards. Awaiting 2 peer approvals.

Review Findings

Category Status
Specification alignment PASS — Closes #980, all acceptance criteria addressed
Commit message format PASS — Conventional Changelog fix(skill): prefix
Code quality PASS — Defensive table check with sqlalchemy.inspect, backward-compatible auto_commit parameter
Testing (Behave) PASS — 2 cross-process scenarios
Testing (Robot) PASS — 2 integration test cases
@tdd_expected_fail removal PASS — Tag removed, @tdd_bug + @tdd_bug_980 remain as regression guards
Issue reference PASS — Closes #980 in body, ISSUES CLOSED: #980 in footer

@hamza.khyari @brent.edwards — please review and approve if findings are satisfactory.

## Day 43 Review — PR #1120 `fix(skill): resolve skill add persistence regression` **Verdict: Review complete — meets all standards. Awaiting 2 peer approvals.** ### Review Findings | Category | Status | |---|---| | Specification alignment | PASS — Closes #980, all acceptance criteria addressed | | Commit message format | PASS — Conventional Changelog `fix(skill):` prefix | | Code quality | PASS — Defensive table check with `sqlalchemy.inspect`, backward-compatible `auto_commit` parameter | | Testing (Behave) | PASS — 2 cross-process scenarios | | Testing (Robot) | PASS — 2 integration test cases | | `@tdd_expected_fail` removal | PASS — Tag removed, `@tdd_bug` + `@tdd_bug_980` remain as regression guards | | Issue reference | PASS — `Closes #980` in body, `ISSUES CLOSED: #980` in footer | @hamza.khyari @brent.edwards — please review and approve if findings are satisfactory.
freemo force-pushed bugfix/m3-skill-add-regression from 159cb7f730
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 3m18s
CI / quality (pull_request) Successful in 3m41s
CI / build (pull_request) Successful in 31s
CI / typecheck (pull_request) Successful in 3m53s
CI / security (pull_request) Successful in 4m6s
CI / integration_tests (pull_request) Failing after 3m59s
CI / unit_tests (pull_request) Successful in 7m11s
CI / docker (pull_request) Successful in 1m12s
CI / e2e_tests (pull_request) Successful in 9m36s
CI / coverage (pull_request) Successful in 11m48s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (pull_request) Failing after 18m13s
to a652d6fb78
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 26s
CI / lint (pull_request) Successful in 3m32s
CI / typecheck (pull_request) Successful in 4m9s
CI / quality (pull_request) Successful in 4m12s
CI / security (pull_request) Successful in 4m36s
CI / unit_tests (pull_request) Successful in 7m40s
CI / integration_tests (pull_request) Successful in 8m37s
CI / docker (pull_request) Successful in 1m23s
CI / e2e_tests (pull_request) Successful in 9m49s
CI / coverage (pull_request) Successful in 11m43s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (pull_request) Failing after 21m31s
2026-03-23 11:51:20 +00:00
Compare
freemo force-pushed bugfix/m3-skill-add-regression from a652d6fb78
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 26s
CI / lint (pull_request) Successful in 3m32s
CI / typecheck (pull_request) Successful in 4m9s
CI / quality (pull_request) Successful in 4m12s
CI / security (pull_request) Successful in 4m36s
CI / unit_tests (pull_request) Successful in 7m40s
CI / integration_tests (pull_request) Successful in 8m37s
CI / docker (pull_request) Successful in 1m23s
CI / e2e_tests (pull_request) Successful in 9m49s
CI / coverage (pull_request) Successful in 11m43s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (pull_request) Failing after 21m31s
to 65d38e4759
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 38s
CI / lint (pull_request) Successful in 5m15s
CI / quality (pull_request) Successful in 5m45s
CI / security (pull_request) Successful in 6m5s
CI / typecheck (pull_request) Successful in 6m10s
CI / unit_tests (pull_request) Successful in 9m4s
CI / docker (pull_request) Successful in 1m16s
CI / integration_tests (pull_request) Successful in 10m47s
CI / e2e_tests (pull_request) Successful in 10m50s
CI / coverage (pull_request) Successful in 11m9s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (pull_request) Failing after 40m42s
2026-03-23 16:48:21 +00:00
Compare
freemo force-pushed bugfix/m3-skill-add-regression from 65d38e4759
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 38s
CI / lint (pull_request) Successful in 5m15s
CI / quality (pull_request) Successful in 5m45s
CI / security (pull_request) Successful in 6m5s
CI / typecheck (pull_request) Successful in 6m10s
CI / unit_tests (pull_request) Successful in 9m4s
CI / docker (pull_request) Successful in 1m16s
CI / integration_tests (pull_request) Successful in 10m47s
CI / e2e_tests (pull_request) Successful in 10m50s
CI / coverage (pull_request) Successful in 11m9s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (pull_request) Failing after 40m42s
to 312aa3d4f8
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / security (pull_request) Successful in 48s
CI / build (pull_request) Successful in 23s
CI / lint (pull_request) Successful in 3m17s
CI / quality (pull_request) Successful in 3m38s
CI / typecheck (pull_request) Successful in 3m47s
CI / integration_tests (pull_request) Successful in 6m51s
CI / e2e_tests (pull_request) Successful in 9m21s
CI / coverage (pull_request) Successful in 11m15s
CI / unit_tests (pull_request) Failing after 15m58s
CI / benchmark-regression (pull_request) Successful in 1h1m33s
CI / docker (pull_request) Has been skipped
CI / status-check (pull_request) Failing after 1s
2026-03-23 22:49:29 +00:00
Compare
freemo force-pushed bugfix/m3-skill-add-regression from 312aa3d4f8
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / security (pull_request) Successful in 48s
CI / build (pull_request) Successful in 23s
CI / lint (pull_request) Successful in 3m17s
CI / quality (pull_request) Successful in 3m38s
CI / typecheck (pull_request) Successful in 3m47s
CI / integration_tests (pull_request) Successful in 6m51s
CI / e2e_tests (pull_request) Successful in 9m21s
CI / coverage (pull_request) Successful in 11m15s
CI / unit_tests (pull_request) Failing after 15m58s
CI / benchmark-regression (pull_request) Successful in 1h1m33s
CI / docker (pull_request) Has been skipped
CI / status-check (pull_request) Failing after 1s
to 75161acf4b
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 19m33s
CI / typecheck (pull_request) Successful in 20m12s
CI / integration_tests (pull_request) Successful in 22m30s
CI / e2e_tests (pull_request) Successful in 24m50s
CI / security (pull_request) Successful in 29m36s
CI / build (pull_request) Failing after 29m38s
CI / quality (pull_request) Successful in 29m46s
CI / coverage (pull_request) Successful in 10m1s
CI / unit_tests (pull_request) Successful in 33m4s
CI / docker (pull_request) Successful in 1m4s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (pull_request) Successful in 52m7s
2026-03-24 01:15:25 +00:00
Compare
freemo force-pushed bugfix/m3-skill-add-regression from 75161acf4b
Some checks failed
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 19m33s
CI / typecheck (pull_request) Successful in 20m12s
CI / integration_tests (pull_request) Successful in 22m30s
CI / e2e_tests (pull_request) Successful in 24m50s
CI / security (pull_request) Successful in 29m36s
CI / build (pull_request) Failing after 29m38s
CI / quality (pull_request) Successful in 29m46s
CI / coverage (pull_request) Successful in 10m1s
CI / unit_tests (pull_request) Successful in 33m4s
CI / docker (pull_request) Successful in 1m4s
CI / status-check (pull_request) Successful in 1s
CI / benchmark-regression (pull_request) Successful in 52m7s
to fe8881b1c4
All checks were successful
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 28s
CI / lint (pull_request) Successful in 3m29s
CI / quality (pull_request) Successful in 3m39s
CI / typecheck (pull_request) Successful in 3m59s
CI / security (pull_request) Successful in 4m3s
CI / e2e_tests (pull_request) Successful in 8m15s
CI / integration_tests (pull_request) Successful in 8m52s
CI / unit_tests (pull_request) Successful in 8m59s
CI / docker (pull_request) Successful in 1m32s
CI / coverage (pull_request) Successful in 12m21s
CI / status-check (pull_request) Successful in 2s
CI / benchmark-regression (pull_request) Successful in 49m51s
2026-03-24 14:26:15 +00:00
Compare
freemo left a comment

Review: Looks Good (with Minor Notes)

Clean, well-documented bug fix that directly addresses both root causes of the cross-process skill persistence regression. The implementation follows established codebase patterns (SessionRepository auto_commit, _build_session_service table creation), maintains backward compatibility (auto_commit defaults to False), and includes thorough test coverage at BDD and Robot levels.

Minor Notes

  1. DRY opportunity. The if self._auto_commit: session.commit(); session.close() block is duplicated in create(), update(), and delete(). Consider extracting to a _finalize_session(session) helper or context manager. Not blocking — consistent with existing SessionRepository pattern.

  2. Session not closed on commit failure. If session.commit() raises (e.g., late IntegrityError), session.close() is skipped. The except block does session.rollback() but never closes. Minor resource hygiene issue — consider adding session.close() to a finally block when auto_commit=True.

  3. PR dependency. PR body states this depends on PR #1110 (TDD test). Ensure #1110 is merged first to avoid conflicts.

Overall this is solid work — the two-pronged fix (table creation + auto_commit) is the right approach.

Note: Cannot formally approve as PR author matches the authenticated API user.

## Review: Looks Good (with Minor Notes) Clean, well-documented bug fix that directly addresses both root causes of the cross-process skill persistence regression. The implementation follows established codebase patterns (`SessionRepository` auto_commit, `_build_session_service` table creation), maintains backward compatibility (`auto_commit` defaults to `False`), and includes thorough test coverage at BDD and Robot levels. ### Minor Notes 1. **DRY opportunity.** The `if self._auto_commit: session.commit(); session.close()` block is duplicated in `create()`, `update()`, and `delete()`. Consider extracting to a `_finalize_session(session)` helper or context manager. Not blocking — consistent with existing `SessionRepository` pattern. 2. **Session not closed on commit failure.** If `session.commit()` raises (e.g., late `IntegrityError`), `session.close()` is skipped. The `except` block does `session.rollback()` but never closes. Minor resource hygiene issue — consider adding `session.close()` to a `finally` block when `auto_commit=True`. 3. **PR dependency.** PR body states this depends on PR #1110 (TDD test). Ensure #1110 is merged first to avoid conflicts. Overall this is solid work — the two-pronged fix (table creation + auto_commit) is the right approach. *Note: Cannot formally approve as PR author matches the authenticated API user.*
freemo force-pushed bugfix/m3-skill-add-regression from fe8881b1c4
All checks were successful
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 28s
CI / lint (pull_request) Successful in 3m29s
CI / quality (pull_request) Successful in 3m39s
CI / typecheck (pull_request) Successful in 3m59s
CI / security (pull_request) Successful in 4m3s
CI / e2e_tests (pull_request) Successful in 8m15s
CI / integration_tests (pull_request) Successful in 8m52s
CI / unit_tests (pull_request) Successful in 8m59s
CI / docker (pull_request) Successful in 1m32s
CI / coverage (pull_request) Successful in 12m21s
CI / status-check (pull_request) Successful in 2s
CI / benchmark-regression (pull_request) Successful in 49m51s
to 93da31e80f
Some checks failed
CI / build (pull_request) Successful in 25s
CI / benchmark-publish (pull_request) Has been skipped
CI / lint (pull_request) Successful in 3m46s
CI / quality (pull_request) Successful in 4m9s
CI / security (pull_request) Successful in 4m13s
CI / typecheck (pull_request) Successful in 4m23s
CI / unit_tests (pull_request) Successful in 6m31s
CI / integration_tests (pull_request) Successful in 7m8s
CI / docker (pull_request) Successful in 1m14s
CI / e2e_tests (pull_request) Successful in 8m28s
CI / coverage (pull_request) Successful in 10m19s
CI / status-check (pull_request) Successful in 1s
CI / build (push) Successful in 24s
CI / lint (push) Successful in 3m36s
CI / quality (push) Successful in 3m41s
CI / typecheck (push) Successful in 3m56s
CI / benchmark-regression (push) Has been skipped
CI / security (push) Successful in 4m4s
CI / integration_tests (push) Successful in 7m1s
CI / coverage (push) Failing after 12m22s
CI / e2e_tests (push) Failing after 16m19s
CI / unit_tests (push) Successful in 18m40s
CI / docker (push) Successful in 57s
CI / status-check (push) Failing after 3s
CI / benchmark-publish (push) Successful in 28m38s
CI / benchmark-regression (pull_request) Successful in 52m22s
2026-03-24 17:08:23 +00:00
Compare
freemo scheduled this pull request to auto merge when all checks succeed 2026-03-24 17:08:36 +00:00
freemo merged commit 93da31e80f into master 2026-03-24 17:23:10 +00:00
freemo deleted branch bugfix/m3-skill-add-regression 2026-03-24 17:23:11 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
cleveragents/cleveragents-core!1120
No description provided.