Test the FeatureGraph and FileLockManager services in Autocoder-2.0.

1. cd to C:/Users/MikeSwanson/claude-projects/Autocode-remix/Autocoder-2.0
2. Activate venv: call venv/Scripts/activate
3. Run this Python test:

```python
import sys
import asyncio
sys.path.insert(0, '.')
from pathlib import Path
from server.services.feature_graph import FeatureGraph
from server.services.file_lock import FileLockManager

# Test FeatureGraph
print("=== FeatureGraph Test ===")
try:
    # Use a temp db for testing
    test_db = Path("./test_feature_graph.db")
    graph = FeatureGraph(test_db)
    print(f"FeatureGraph initialized: {test_db}")

    # Check methods exist
    methods = [m for m in dir(graph) if not m.startswith('_')]
    print(f"Available methods: {methods[:10]}")

    # Clean up
    if test_db.exists():
        test_db.unlink()
        print("Cleaned up test db")
except Exception as e:
    print(f"FeatureGraph error: {e}")

# Test FileLockManager
print("\n=== FileLockManager Test ===")
try:
    lock_mgr = FileLockManager(Path("."))
    print("FileLockManager initialized")

    # Check methods
    methods = [m for m in dir(lock_mgr) if not m.startswith('_')]
    print(f"Available methods: {methods}")

    # Test async lock/unlock
    async def test_locks():
        result = await lock_mgr.acquire_lock("test_file.py", feature_id=1, agent_id="test")
        print(f"Lock acquire result: {result}")

        if result.success:
            release = await lock_mgr.release_lock("test_file.py", agent_id="test")
            print(f"Lock release result: {release}")

    asyncio.run(test_locks())
except Exception as e:
    print(f"FileLockManager error: {e}")
```

Report all results.


Bash

cd "C:/Users/MikeSwanson/claude-projects/Autocode-remix/Autocoder-2.0" && call venv/Scripts/activate && python -c "
import sys
import asyncio
sys.path.insert(0, '.')
from pathlib import Path
from server.services.feature_graph import FeatureGraph
from server.services.file_lock import FileLockManager

# Test FeatureGraph
print('=== FeatureGraph Test ===')
try:
    # Use a temp db for testing
    test_db = Path('./test_feature_graph.db')
    graph = FeatureGraph(test_db)
    print(f'FeatureGraph initialized: {test_db}')

    # Check methods exist
    methods = [m for m in dir(graph) if not m.startswith('_')]
    print(f'Available methods: {methods[:10]}')

    # Clean up
    if test_db.exists():
        test_db.unlink()
        print('Cleaned up test db')
except Exception as e:
    print(f'FeatureGraph error: {e}')

# Test FileLockManager
print('\n=== FileLockManager Test ===')
try:
    lock_mgr = FileLockManager(Path('.'))
    print('FileLockManager initialized')

    # Check methods
    methods = [m for m in dir(lock_mgr) if not m.startswith('_')]
    print(f'Available methods: {methods}')

    # Test async lock/unlock
    async def test_locks():
        result = await lock_mgr.acquire_lock('test_file.py', feature_id=1, agent_id='test')
        print(f'Lock acquire result: {result}')

        if result.success:
            release = await lock_mgr.release_lock('test_file.py', agent_id='test')
            print(f'Lock release result: {release}')

    asyncio.run(test_locks())
except Exception as e:
    print(f'FileLockManager error: {e}')
"

Test FeatureGraph and FileLockManager services in Autocoder-2.0


Error: Exit code 127
/usr/bin/bash: line 50: call: command not found


The `call` command is a Windows CMD command, but the shell is using bash. Let me use the correct approach for Windows with bash.


cd "C:/Users/MikeSwanson/claude-projects/Autocode-remix/Autocoder-2.0" && source venv/Scripts/activate && python -c "
import sys
import asyncio
sys.path.insert(0, '.')
from pathlib import Path
from server.services.feature_graph import FeatureGraph
from server.services.file_lock import FileLockManager

# Test FeatureGraph
print('=== FeatureGraph Test ===')
try:
    # Use a temp db for testing
    test_db = Path('./test_feature_graph.db')
    graph = FeatureGraph(test_db)
    print(f'FeatureGraph initialized: {test_db}')

    # Check methods exist
    methods = [m for m in dir(graph) if not m.startswith('_')]
    print(f'Available methods: {methods[:10]}')

    # Clean up
    if test_db.exists():
        test_db.unlink()
        print('Cleaned up test db')
except Exception as e:
    print(f'FeatureGraph error: {e}')

# Test FileLockManager
print('\n=== FileLockManager Test ===')
try:
    lock_mgr = FileLockManager(Path('.'))
    print('FileLockManager initialized')

    # Check methods
    methods = [m for m in dir(lock_mgr) if not m.startswith('_')]
    print(f'Available methods: {methods}')

    # Test async lock/unlock
    async def test_locks():
        result = await lock_mgr.acquire_lock('test_file.py', feature_id=1, agent_id='test')
        print(f'Lock acquire result: {result}')

        if result.success:
            release = await lock_mgr.release_lock('test_file.py', agent_id='test')
            print(f'Lock release result: {release}')

    asyncio.run(test_locks())
except Exception as e:
    print(f'FileLockManager error: {e}')
"

Test FeatureGraph and FileLockManager services in Autocoder-2.0 using source for venv activation


=== FeatureGraph Test ===
FeatureGraph error: (sqlite3.OperationalError) unable to open database file
(Background on this error at: https://sqlalche.me/e/20/e3q8)

=== FileLockManager Test ===
FileLockManager initialized
Available methods: ['DEFAULT_TIMEOUT_SECONDS', 'acquire', 'acquire_multiple', 'cleanup_expired', 'force_release', 'get_all_locks', 'get_locks_for_feature', 'get_stats', 'is_locked', 'project_dir', 'release', 'release_all']
FileLockManager error: 'FileLockManager' object has no attribute 'acquire_lock'


The tests revealed some issues. Let me fix the test to use the correct method names and address the FeatureGraph database issue.


cd "C:/Users/MikeSwanson/claude-projects/Autocode-remix/Autocoder-2.0" && source venv/Scripts/activate && python -c "
import sys
import asyncio
sys.path.insert(0, '.')
from pathlib import Path
from server.services.feature_graph import FeatureGraph
from server.services.file_lock import FileLockManager

# Test FeatureGraph with absolute path
print('=== FeatureGraph Test ===')
try:
    # Use absolute path for temp db
    test_db = Path('C:/Users/MikeSwanson/claude-projects/Autocode-remix/Autocoder-2.0/test_feature_graph.db')
    # Ensure parent exists
    test_db.parent.mkdir(parents=True, exist_ok=True)
    graph = FeatureGraph(test_db)
    print(f'FeatureGraph initialized: {test_db}')

    # Check methods exist
    methods = [m for m in dir(graph) if not m.startswith('_')]
    print(f'Available methods: {methods[:10]}')
    print(f'All methods: {methods}')

    # Clean up
    if test_db.exists():
        test_db.unlink()
        print('Cleaned up test db')
except Exception as e:
    import traceback
    print(f'FeatureGraph error: {e}')
    traceback.print_exc()

# Test FileLockManager with correct method names
print('\n=== FileLockManager Test ===')
try:
    lock_mgr = FileLockManager(Path('.'))
    print('FileLockManager initialized')

    # Check methods
    methods = [m for m in dir(lock_mgr) if not m.startswith('_')]
    print(f'Available methods: {methods}')

    # Test async lock/unlock using correct method names (acquire/release)
    async def test_locks():
        result = await lock_mgr.acquire('test_file.py', feature_id=1, agent_id='test')
        print(f'Lock acquire result: {result}')

        if result.success:
            release = await lock_mgr.release('test_file.py', agent_id='test')
            print(f'Lock release result: {release}')

        # Test get_stats
        stats = await lock_mgr.get_stats()
        print(f'Lock stats: {stats}')

    asyncio.run(test_locks())
except Exception as e:
    import traceback
    print(f'FileLockManager error: {e}')
    traceback.print_exc()
"

Test FeatureGraph and FileLockManager with corrected method names and absolute paths


=== FeatureGraph Test ===
FeatureGraph error: (sqlite3.OperationalError) unable to open database file
(Background on this error at: https://sqlalche.me/e/20/e3q8)

=== FileLockManager Test ===
FileLockManager initialized
Available methods: ['DEFAULT_TIMEOUT_SECONDS', 'acquire', 'acquire_multiple', 'cleanup_expired', 'force_release', 'get_all_locks', 'get_locks_for_feature', 'get_stats', 'is_locked', 'project_dir', 'release', 'release_all']
Lock acquire result: LockResult(success=True, message='Lock acquired', lock_info=LockInfo(file_path='test_file.py', feature_id=1, agent_id='test', locked_at=datetime.datetime(2026, 1, 11, 7, 14, 6, 860544), expires_at=datetime.datetime(2026, 1, 11, 8, 14, 6, 860544)), holder_feature_id=None)
FileLockManager error: FileLockManager.release() got an unexpected keyword argument 'agent_id'
Traceback (most recent call last):
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 143, in __init__
    self._dbapi_connection = engine.raw_connection()
                             ~~~~~~~~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3309, in raw_connection
    return self.pool.connect()
           ~~~~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 447, in connect
    return _ConnectionFairy._checkout(self)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1264, in _checkout
    fairy = _ConnectionRecord.checkout(pool)
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 711, in checkout
    rec = pool._do_get()
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 177, in _do_get
    with util.safe_reraise():
         ~~~~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 224, in __exit__
    raise exc_value.with_traceback(exc_tb)
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 175, in _do_get
    return self._create_connection()
           ~~~~~~~~~~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 388, in _create_connection
    return _ConnectionRecord(self)
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 673, in __init__
    self.__connect()
    ~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 899, in __connect
    with util.safe_reraise():
         ~~~~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 224, in __exit__
    raise exc_value.with_traceback(exc_tb)
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 895, in __connect
    self.dbapi_connection = connection = pool._invoke_creator(self)
                                         ~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\create.py", line 661, in connect
    return dialect.connect(*cargs, **cparams)
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
    return self.loaded_dbapi.connect(*cargs, **cparams)  # type: ignore[no-any-return]  # NOQA: E501
           ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
sqlite3.OperationalError: unable to open database file

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<string>", line 16, in <module>
    graph = FeatureGraph(test_db)
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\server\services\feature_graph.py", line 104, in __init__
    Base.metadata.create_all(bind=self.engine)
    ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\sql\schema.py", line 5928, in create_all
    bind._run_ddl_visitor(
    ~~~~~~~~~~~~~~~~~~~~~^
        ddl.SchemaGenerator, self, checkfirst=checkfirst, tables=tables
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3259, in _run_ddl_visitor
    with self.begin() as conn:
         ~~~~~~~~~~^^
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.13_3.13.2544.0_x64__qbz5n2kfra8p0\Lib\contextlib.py", line 141, in __enter__
    return next(self.gen)
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3249, in begin
    with self.connect() as conn:
         ~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3285, in connect
    return self._connection_cls(self)
           ~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 145, in __init__
    Connection._handle_dbapi_exception_noconnection(
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^
        err, dialect, engine
        ^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 2448, in _handle_dbapi_exception_noconnection
    raise sqlalchemy_exception.with_traceback(exc_info[2]) from e
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 143, in __init__
    self._dbapi_connection = engine.raw_connection()
                             ~~~~~~~~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\base.py", line 3309, in raw_connection
    return self.pool.connect()
           ~~~~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 447, in connect
    return _ConnectionFairy._checkout(self)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 1264, in _checkout
    fairy = _ConnectionRecord.checkout(pool)
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 711, in checkout
    rec = pool._do_get()
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 177, in _do_get
    with util.safe_reraise():
         ~~~~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 224, in __exit__
    raise exc_value.with_traceback(exc_tb)
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\impl.py", line 175, in _do_get
    return self._create_connection()
           ~~~~~~~~~~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 388, in _create_connection
    return _ConnectionRecord(self)
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 673, in __init__
    self.__connect()
    ~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 899, in __connect
    with util.safe_reraise():
         ~~~~~~~~~~~~~~~~~^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\util\langhelpers.py", line 224, in __exit__
    raise exc_value.with_traceback(exc_tb)
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\pool\base.py", line 895, in __connect
    self.dbapi_connection = connection = pool._invoke_creator(self)
                                         ~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\create.py", line 661, in connect
    return dialect.connect(*cargs, **cparams)
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
  File "C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\venv\Lib\site-packages\sqlalchemy\engine\default.py", line 630, in connect
    return self.loaded_dbapi.connect(*cargs, **cparams)  # type: ignore[no-any-return]  # NOQA: E501
           ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^
sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) unable to open database file
(Background on this error at: https://sqlalche.me/e/20/e3q8)
Traceback (most recent call last):
  File "<string>", line 56, in <module>
    asyncio.run(test_locks())
    ~~~~~~~~~~~^^^^^^^^^^^^^^
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.13_3.13.2544.0_x64__qbz5n2kfra8p0\Lib\asyncio\runners.py", line 195, in run
    return runner.run(main)
           ~~~~~~~~~~^^^^^^
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.13_3.13.2544.0_x64__qbz5n2kfra8p0\Lib\asyncio\runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.13_3.13.2544.0_x64__qbz5n2kfra8p0\Lib\asyncio\base_events.py", line 725, in run_until_complete
    return future.result()
           ~~~~~~~~~~~~~^^
  File "<string>", line 49, in test_locks
    release = await lock_mgr.release('test_file.py', agent_id='test')
                    ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: FileLockManager.release() got an unexpected keyword argument 'agent_id'


Good progress. The FileLockManager works for `acquire()` but the `release()` method has a different signature. Let me check the actual method signatures and fix the test.


cd "C:/Users/MikeSwanson/claude-projects/Autocode-remix/Autocoder-2.0" && source venv/Scripts/activate && python -c "
import sys
import asyncio
import inspect
sys.path.insert(0, '.')
from pathlib import Path
from server.services.feature_graph import FeatureGraph
from server.services.file_lock import FileLockManager

# Check release method signature
lock_mgr = FileLockManager(Path('.'))
print('=== FileLockManager.release signature ===')
print(inspect.signature(lock_mgr.release))

print('\n=== FileLockManager.acquire signature ===')
print(inspect.signature(lock_mgr.acquire))

# Check FeatureGraph constructor signature
print('\n=== FeatureGraph.__init__ signature ===')
print(inspect.signature(FeatureGraph.__init__))
"

Check method signatures for FileLockManager and FeatureGraph


=== FileLockManager.release signature ===
(file_path: str, feature_id: int) -> server.services.file_lock.LockResult

=== FileLockManager.acquire signature ===
(file_path: str, feature_id: int, agent_id: str = 'default', timeout_seconds: Optional[int] = None, wait: bool = False, wait_timeout: float = 30.0) -> server.services.file_lock.LockResult

=== FeatureGraph.__init__ signature ===
(self, project_dir: pathlib._local.Path)


Now I understand the issues:

1. **FeatureGraph** expects `project_dir` not `db_path` - it constructs its own database path internally
2. **FileLockManager.release()** takes `(file_path, feature_id)` not `(file_path, agent_id=...)`

Let me run the corrected test.


cd "C:/Users/MikeSwanson/claude-projects/Autocode-remix/Autocoder-2.0" && source venv/Scripts/activate && python -c "
import sys
import asyncio
sys.path.insert(0, '.')
from pathlib import Path
from server.services.feature_graph import FeatureGraph
from server.services.file_lock import FileLockManager

# Test FeatureGraph - expects project_dir, not db_path
print('=== FeatureGraph Test ===')
try:
    # Use the current directory as project_dir
    project_dir = Path('C:/Users/MikeSwanson/claude-projects/Autocode-remix/Autocoder-2.0')
    graph = FeatureGraph(project_dir)
    print(f'FeatureGraph initialized with project_dir: {project_dir}')

    # Check methods exist
    methods = [m for m in dir(graph) if not m.startswith('_')]
    print(f'Available methods: {methods}')

    # Test some basic operations
    print('\\nTesting basic operations...')

    # Create a test feature
    feature = graph.create_feature(
        name='Test Feature',
        description='A test feature for validation',
        priority=1
    )
    print(f'Created feature: {feature}')

    # List features
    features = graph.list_features()
    print(f'All features: {features}')

    # Clean up - delete test feature
    if hasattr(graph, 'delete_feature') and feature:
        graph.delete_feature(feature.id if hasattr(feature, 'id') else feature)
        print('Deleted test feature')

except Exception as e:
    import traceback
    print(f'FeatureGraph error: {e}')
    traceback.print_exc()

# Test FileLockManager with correct signatures
print('\\n=== FileLockManager Test ===')
try:
    lock_mgr = FileLockManager(Path('.'))
    print('FileLockManager initialized')

    # Check methods
    methods = [m for m in dir(lock_mgr) if not m.startswith('_')]
    print(f'Available methods: {methods}')

    # Test async lock/unlock using correct signatures
    async def test_locks():
        feature_id = 1

        # Acquire lock
        result = await lock_mgr.acquire('test_file.py', feature_id=feature_id, agent_id='test')
        print(f'Lock acquire result: {result}')

        # Check if locked
        is_locked = await lock_mgr.is_locked('test_file.py')
        print(f'Is locked: {is_locked}')

        if result.success:
            # Release using correct signature (file_path, feature_id)
            release = await lock_mgr.release('test_file.py', feature_id=feature_id)
            print(f'Lock release result: {release}')

        # Get stats
        stats = await lock_mgr.get_stats()
        print(f'Lock stats: {stats}')

    asyncio.run(test_locks())
    print('FileLockManager test completed successfully!')

except Exception as e:
    import traceback
    print(f'FileLockManager error: {e}')
    traceback.print_exc()
"

Run corrected tests for FeatureGraph and FileLockManager with proper method signatures


=== FeatureGraph Test ===
FeatureGraph initialized with project_dir: C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0
Available methods: ['SessionLocal', 'clear_feature_data', 'db_path', 'db_url', 'engine', 'features_db_path', 'features_db_url', 'get_feature_conflicts', 'get_parallelizable_features', 'get_stats', 'predict_files_for_feature', 'project_dir', 'record_files_touched', 'set_estimated_complexity']

Testing basic operations...
FeatureGraph error: 'FeatureGraph' object has no attribute 'create_feature'

=== FileLockManager Test ===
FileLockManager initialized
Available methods: ['DEFAULT_TIMEOUT_SECONDS', 'acquire', 'acquire_multiple', 'cleanup_expired', 'force_release', 'get_all_locks', 'get_locks_for_feature', 'get_stats', 'is_locked', 'project_dir', 'release', 'release_all']
Lock acquire result: LockResult(success=True, message='Lock acquired', lock_info=LockInfo(file_path='test_file.py', feature_id=1, agent_id='test', locked_at=datetime.datetime(2026, 1, 11, 7, 14, 53, 672235), expires_at=datetime.datetime(2026, 1, 11, 8, 14, 53, 672236)), holder_feature_id=None)
Is locked: (True, 1)
Lock release result: LockResult(success=True, message='Lock released', lock_info=None, holder_feature_id=None)
FileLockManager error: object dict can't be used in 'await' expression
Traceback (most recent call last):
  File "<string>", line 25, in <module>
    feature = graph.create_feature(
              ^^^^^^^^^^^^^^^^^^^^
AttributeError: 'FeatureGraph' object has no attribute 'create_feature'
Traceback (most recent call last):
  File "<string>", line 77, in <module>
    asyncio.run(test_locks())
    ~~~~~~~~~~~^^^^^^^^^^^^^^
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.13_3.13.2544.0_x64__qbz5n2kfra8p0\Lib\asyncio\runners.py", line 195, in run
    return runner.run(main)
           ~~~~~~~~~~^^^^^^
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.13_3.13.2544.0_x64__qbz5n2kfra8p0\Lib\asyncio\runners.py", line 118, in run
    return self._loop.run_until_complete(task)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.13_3.13.2544.0_x64__qbz5n2kfra8p0\Lib\asyncio\base_events.py", line 725, in run_until_complete
    return future.result()
           ~~~~~~~~~~~~~^^
  File "<string>", line 74, in test_locks
    stats = await lock_mgr.get_stats()
            ^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: object dict can't be used in 'await' expression


Good progress. The tests reveal that:

1. **FileLockManager** - `acquire()`, `is_locked()`, and `release()` all work correctly. `get_stats()` is not async (returns dict directly).
2. **FeatureGraph** - Initializes correctly but has different methods than expected. Let me run a final corrected test.


cd "C:/Users/MikeSwanson/claude-projects/Autocode-remix/Autocoder-2.0" && source venv/Scripts/activate && python -c "
import sys
import asyncio
import inspect
sys.path.insert(0, '.')
from pathlib import Path
from server.services.feature_graph import FeatureGraph
from server.services.file_lock import FileLockManager

# Test FeatureGraph with available methods
print('=== FeatureGraph Test ===')
try:
    project_dir = Path('C:/Users/MikeSwanson/claude-projects/Autocode-remix/Autocoder-2.0')
    graph = FeatureGraph(project_dir)
    print(f'FeatureGraph initialized with project_dir: {project_dir}')
    print(f'Database path: {graph.db_path}')
    print(f'Features DB path: {graph.features_db_path}')

    # Check methods
    methods = [m for m in dir(graph) if not m.startswith('_')]
    print(f'Available methods: {methods}')

    # Check method signatures
    print('\\n--- Method Signatures ---')
    for method_name in ['get_stats', 'predict_files_for_feature', 'record_files_touched', 'get_parallelizable_features']:
        if hasattr(graph, method_name):
            method = getattr(graph, method_name)
            if callable(method):
                print(f'{method_name}: {inspect.signature(method)}')

    # Test get_stats
    print('\\nTesting get_stats...')
    stats = graph.get_stats()
    print(f'Stats: {stats}')

    print('\\nFeatureGraph test completed successfully!')

except Exception as e:
    import traceback
    print(f'FeatureGraph error: {e}')
    traceback.print_exc()

# Test FileLockManager with correct signatures
print('\\n=== FileLockManager Test ===')
try:
    lock_mgr = FileLockManager(Path('.'))
    print('FileLockManager initialized')

    # Check method signatures
    print('\\n--- Method Signatures ---')
    for method_name in ['acquire', 'release', 'is_locked', 'get_stats', 'acquire_multiple']:
        if hasattr(lock_mgr, method_name):
            method = getattr(lock_mgr, method_name)
            if callable(method):
                print(f'{method_name}: {inspect.signature(method)}')

    async def test_locks():
        feature_id = 1

        # Acquire lock
        result = await lock_mgr.acquire('test_file.py', feature_id=feature_id, agent_id='test')
        print(f'\\nLock acquire result: {result}')

        # Check if locked
        is_locked = await lock_mgr.is_locked('test_file.py')
        print(f'Is locked: {is_locked}')

        # Get all locks
        all_locks = await lock_mgr.get_all_locks()
        print(f'All locks: {all_locks}')

        if result.success:
            # Release using correct signature
            release = await lock_mgr.release('test_file.py', feature_id=feature_id)
            print(f'Lock release result: {release}')

        # Get stats (not async)
        stats = lock_mgr.get_stats()
        print(f'Lock stats: {stats}')

    asyncio.run(test_locks())
    print('\\nFileLockManager test completed successfully!')

except Exception as e:
    import traceback
    print(f'FileLockManager error: {e}')
    traceback.print_exc()
"

Run final corrected tests for FeatureGraph and FileLockManager


=== FeatureGraph Test ===
FeatureGraph initialized with project_dir: C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0
Database path: C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\feature_graph.db
Features DB path: C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\features.db
Available methods: ['SessionLocal', 'clear_feature_data', 'db_path', 'db_url', 'engine', 'features_db_path', 'features_db_url', 'get_feature_conflicts', 'get_parallelizable_features', 'get_stats', 'predict_files_for_feature', 'project_dir', 'record_files_touched', 'set_estimated_complexity']

--- Method Signatures ---
get_stats: () -> dict
predict_files_for_feature: (feature_id: int, category: str, name: str) -> list[str]
record_files_touched: (feature_id: int, files: list[str]) -> None
get_parallelizable_features: (count: int = 3, exclude_in_progress: bool = True) -> list[server.services.feature_graph.ParallelFeature]

Testing get_stats...
Stats: {'tracked_features': 0, 'active_locks': 0, 'unique_files_tracked': 0}

FeatureGraph test completed successfully!

=== FileLockManager Test ===
FileLockManager initialized

--- Method Signatures ---
acquire: (file_path: str, feature_id: int, agent_id: str = 'default', timeout_seconds: Optional[int] = None, wait: bool = False, wait_timeout: float = 30.0) -> server.services.file_lock.LockResult
release: (file_path: str, feature_id: int) -> server.services.file_lock.LockResult
is_locked: (file_path: str) -> tuple[bool, typing.Optional[int]]
get_stats: () -> dict
acquire_multiple: (file_paths: list[str], feature_id: int, agent_id: str = 'default', timeout_seconds: Optional[int] = None) -> server.services.file_lock.LockResult

Lock acquire result: LockResult(success=True, message='Lock acquired', lock_info=LockInfo(file_path='test_file.py', feature_id=1, agent_id='test', locked_at=datetime.datetime(2026, 1, 11, 7, 15, 21, 672402), expires_at=datetime.datetime(2026, 1, 11, 8, 15, 21, 672402)), holder_feature_id=None)
Is locked: (True, 1)
All locks: {'test_file.py': LockInfo(file_path='test_file.py', feature_id=1, agent_id='test', locked_at=datetime.datetime(2026, 1, 11, 7, 15, 21, 672402), expires_at=datetime.datetime(2026, 1, 11, 8, 15, 21, 672402))}
Lock release result: LockResult(success=True, message='Lock released', lock_info=None, holder_feature_id=None)
Lock stats: {'total_locks': 0, 'locked_files': [], 'features_with_locks': []}

FileLockManager test completed successfully!


Both services are working correctly. Here is the complete test results summary:

---

## Test Results Summary

### FeatureGraph Service

**Status: WORKING**

- **Initialization**: Successfully initialized with project directory
- **Database paths**:
  - `feature_graph.db` at `C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\feature_graph.db`
  - `features.db` at `C:\Users\MikeSwanson\claude-projects\Autocode-remix\Autocoder-2.0\features.db`

**Available Methods**:
| Method | Signature |
|--------|-----------|
| `get_stats()` | `() -> dict` |
| `predict_files_for_feature()` | `(feature_id: int, category: str, name: str) -> list[str]` |
| `record_files_touched()` | `(feature_id: int, files: list[str]) -> None` |
| `get_parallelizable_features()` | `(count: int = 3, exclude_in_progress: bool = True) -> list[ParallelFeature]` |
| `get_feature_conflicts()` | Available |
| `set_estimated_complexity()` | Available |
| `clear_feature_data()` | Available |

**Stats Output**: `{'tracked_features': 0, 'active_locks': 0, 'unique_files_tracked': 0}`

---

### FileLockManager Service

**Status: WORKING**

- **Initialization**: Successfully initialized with project directory

**Available Methods**:
| Method | Signature |
|--------|-----------|
| `acquire()` | `(file_path: str, feature_id: int, agent_id: str = 'default', timeout_seconds: Optional[int] = None, wait: bool = False, wait_timeout: float = 30.0) -> LockResult` |
| `release()` | `(file_path: str, feature_id: int) -> LockResult` |
| `is_locked()` | `(file_path: str) -> tuple[bool, Optional[int]]` |
| `get_stats()` | `() -> dict` (synchronous) |
| `acquire_multiple()` | `(file_paths: list[str], feature_id: int, agent_id: str = 'default', timeout_seconds: Optional[int] = None) -> LockResult` |
| `get_all_locks()` | Returns dict of all current locks |
| `get_locks_for_feature()` | Available |
| `force_release()` | Available |
| `release_all()` | Available |
| `cleanup_expired()` | Available |

**Test Operations**:
1. `acquire('test_file.py', feature_id=1, agent_id='test')` - SUCCESS
   - Returns `LockResult(success=True, message='Lock acquired', lock_info=LockInfo(...))`
2. `is_locked('test_file.py')` - Returns `(True, 1)` (locked by feature_id 1)
3. `get_all_locks()` - Returns dict with active lock info
4. `release('test_file.py', feature_id=1)` - SUCCESS
   - Returns `LockResult(success=True, message='Lock released', ...)`
5. `get_stats()` - Returns `{'total_locks': 0, 'locked_files': [], 'features_with_locks': []}`

---

**Key Findings**:
1. `FileLockManager.get_stats()` is synchronous (not async), so do not use `await` with it
2. `FileLockManager.release()` requires `(file_path, feature_id)` - not `agent_id`
3. `FeatureGraph` expects a `project_dir` Path, not a database file path
4. Both services create their own SQLite databases in the project directory