feat(auto_review): add stability ring detection and thresholds #15
77
ai-memory/agent-notes.md
Normal file
77
ai-memory/agent-notes.md
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
# Agent Notes — Chronological Observations
|
||||||
|
|
||||||
|
This file records decisions, protocol adoptions, and notable observations made by the agents during development.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2026-03-15
|
||||||
|
|
||||||
|
### Morning: Sibling Branch Integration
|
||||||
|
|
||||||
|
- Merged `aitbc1/debug-services` into `main`.
|
||||||
|
- Resolved conflicts in `cli/aitbc_cli/main.py` (AI command group import and registration) and `pyproject.toml` (dependencies and packaging).
|
||||||
|
- Added missing dependencies to CLI: `numpy`, `pandas`, `aiohttp`, `fastapi`, `uvicorn`.
|
||||||
|
- Fixed name shadowing in `regulatory.py` by renaming imports to `_svc` suffix.
|
||||||
|
- Fixed corrupted `apps/blockchain-node/src/aitbc_chain/app.py` (removed duplicate lines, bad indentation).
|
||||||
|
- Confirmed all CLI commands now work: `surveillance`, `ai-trading`, `advanced-analytics`, `regulatory`, `compliance`, `ai-surveillance`.
|
||||||
|
|
||||||
|
### Brother Chain Launch
|
||||||
|
|
||||||
|
- Created brother node config with `.env` and genesis YAML.
|
||||||
|
- Launched P2P node (port 8010) and RPC server (port 8011).
|
||||||
|
- Health endpoint returned OK and supported chain `aitbc-brother-chain`.
|
||||||
|
- Minted 500 AITBC to a test wallet address using `mintFaucet` RPC with correct `chain_id`.
|
||||||
|
- Note: Chain not producing blocks because proposer not set as authority in consensus. Could be addressed later by updating genesis.
|
||||||
|
|
||||||
|
### Coordination Protocols Adopted
|
||||||
|
|
||||||
|
- **AITBC Collaborative Development Protocol**: Issues as task queue; PRs require approval from sibling; no direct pushes to `main`.
|
||||||
|
- **Dependency & Blocked Task Protocol**: Use `blocked` label; address blocking issues first.
|
||||||
|
- **Design Escalation Protocol**: Use `needs-design` for architectural decisions; wait for resolution before implementation.
|
||||||
|
- **Bug Reproduction Protocol**: Never fix without a reproducible test; create failing test first.
|
||||||
|
- **Safe Starter Task Protocol**: Prefer `good-first-task-for-agent` for small, isolated tasks.
|
||||||
|
- **Task Claim Branch**: Use `claim/<issue>` as atomic lock before work; prevents duplicate effort.
|
||||||
|
- **Auto-Review & PR Creation**: Created scripts:
|
||||||
|
- `create_pr.py` – creates PR and auto-requests review from sibling
|
||||||
|
- `auto_review.py` – fetches sibling PRs, runs validation, posts APPROVE or REQUEST_CHANGES
|
||||||
|
- `select_task.py` – task economy selector (utility scoring) + claim branch creation
|
||||||
|
- `monitor-prs.py` – simple status monitor (legacy)
|
||||||
|
- **Confidence Scoring**: Implemented in auto_review with thresholds; will later add ring-based thresholds.
|
||||||
|
- **Stability Rings**: Defined Ring0 (core), Ring1 (platform), Ring2 (app), Ring3 (experimental). Ring detection added to `auto_review.py` (PR #13).
|
||||||
|
|
||||||
|
### Repository Enhancements Proposed
|
||||||
|
|
||||||
|
- **ai-memory/** directory to store:
|
||||||
|
- `bug-patterns.md` (known patterns)
|
||||||
|
- `architecture.md` (structure and conventions)
|
||||||
|
- `debugging-playbook.md` (troubleshooting)
|
||||||
|
- `agent-notes.md` (this file)
|
||||||
|
- `failure-archive/` (lessons from lost PRs)
|
||||||
|
|
||||||
|
Not yet created; awaiting confirmation.
|
||||||
|
|
||||||
|
### Open PRs
|
||||||
|
|
||||||
|
- **PR #11** (`aitbc/7-add-tests-for-aitbc-core`): Test suite for `aitbc-core` with ~94% coverage. Review requested from `aitbc1`.
|
||||||
|
- **PR #12** (`aitbc/4-create-readme-for-agent-sdk`): Added README. Review requested from `aitbc1`.
|
||||||
|
- **PR #13** (`aitbc/13-stability-rings`): Implemented ring detection and thresholding in `auto_review.py`. Review requested from `aitbc1`.
|
||||||
|
|
||||||
|
### Pending Critical Work
|
||||||
|
|
||||||
|
- `aitbc1` must rebase `fix-imports-docs` onto `origin/main` (keeping `generate_sar_svc` pattern) and push. This will create PR #10.
|
||||||
|
- After PR #10 appears, `auto_review.py` should validate and `aitbc` will approve if correct.
|
||||||
|
- All PRs need to be merged after approvals; then agents pull latest `main`.
|
||||||
|
- Set up cron jobs for `auto_review.py` (10 min) and `select_task.py` (30 min) on both agents.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Insights
|
||||||
|
|
||||||
|
- Name shadowing between CLI command functions and service imports is a common pitfall; always alias.
|
||||||
|
- Multi-agent coordination requires atomic locks (claim branches) and explicit review assignment.
|
||||||
|
- Confidence scoring and stability rings help enforce appropriate caution for core vs. app code.
|
||||||
|
- A repository memory layer (bug patterns, architecture, failure archive) prevents rediscovering dead ends.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Notes continue as the project evolves.*
|
||||||
129
ai-memory/architecture.md
Normal file
129
ai-memory/architecture.md
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
# Architecture Overview
|
||||||
|
|
||||||
|
This document records the high-level structure of the AITBC codebase, important conventions, and module responsibilities.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Repository Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
/opt/aitbc/
|
||||||
|
├── apps/
|
||||||
|
│ ├── blockchain-node/ # AITBC blockchain node implementation
|
||||||
|
│ │ └── src/aitbc_chain/
|
||||||
|
│ │ ├── app.py # FastAPI app with RPC and WebSocket
|
||||||
|
│ │ ├── consensus/ # PoA consensus implementation
|
||||||
|
│ │ ├── database.py # SQLite DB for chain state
|
||||||
|
│ │ ├── gossip/ # P2P gossip layer
|
||||||
|
│ │ ├── mempool.py # Transaction pool
|
||||||
|
│ │ ├── models.py # Chain data models
|
||||||
|
│ │ └── rpc/ # RPC endpoints
|
||||||
|
│ │
|
||||||
|
│ ├── coordinator-api/ # Coordinator service (orchestration)
|
||||||
|
│ │ └── src/app/
|
||||||
|
│ │ ├── main.py
|
||||||
|
│ │ ├── routers/
|
||||||
|
│ │ │ ├── blockchain.py
|
||||||
|
│ │ │ ├── marketplace_gpu.py
|
||||||
|
│ │ │ └── ...
|
||||||
|
│ │ └── services/
|
||||||
|
│ │ ├── trading_surveillance.py
|
||||||
|
│ │ ├── ai_trading_engine.py
|
||||||
|
│ │ ├── advanced_analytics.py
|
||||||
|
│ │ ├── ai_surveillance.py
|
||||||
|
│ │ └── regulatory_reporting.py
|
||||||
|
│ │
|
||||||
|
│ └── wallet-daemon/ # Wallet management daemon
|
||||||
|
│ └── src/...
|
||||||
|
│
|
||||||
|
├── cli/
|
||||||
|
│ └── aitbc_cli/
|
||||||
|
│ ├── main.py # Click entrypoint
|
||||||
|
│ ├── commands/ # CLI command groups
|
||||||
|
│ │ ├── surveillance.py
|
||||||
|
│ │ ├── ai_trading.py
|
||||||
|
│ │ ├── advanced_analytics.py
|
||||||
|
│ │ ├── regulatory.py
|
||||||
|
│ │ ├── compliance.py
|
||||||
|
│ │ ├── ai_surveillance.py
|
||||||
|
│ │ └── ai.py # AI provider commands
|
||||||
|
│ └── core/ # CLI core logic
|
||||||
|
│ └── chain_manager.py
|
||||||
|
│
|
||||||
|
├── packages/py/
|
||||||
|
│ ├── aitbc-core/ # Core utilities (logging, crypto helpers)
|
||||||
|
│ │ └── src/aitbc/logging/
|
||||||
|
│ ├── aitbc-sdk/ # Blockchain SDK
|
||||||
|
│ └── aitbc-agent-sdk/ # Agent-specific SDK (README added 2026-03-15)
|
||||||
|
│
|
||||||
|
├── genesis_*.yaml # Genesis configurations for different chains
|
||||||
|
├── pyproject.toml # Root project (CLI packages)
|
||||||
|
└── README.md # Top-level project readme
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Important Conventions
|
||||||
|
|
||||||
|
### Import Structure
|
||||||
|
|
||||||
|
- **Service modules** live under `apps/coordinator-api/src/app/services/`. They should not rely on relative imports within the `app` package; instead, use absolute imports from the Python path when the package is installed. CLI commands add the service directory to `sys.path` at runtime.
|
||||||
|
|
||||||
|
- **CLI commands** are organized as Click command groups. Avoid naming command functions the same as imported service functions to prevent shadowing. Use aliasing if needed (`generate_sar as generate_sar_svc`).
|
||||||
|
|
||||||
|
- **Package dependencies**: The root `pyproject.toml` builds the `aitbc-cli` package. Service-specific dependencies should be listed there if used by CLI, or in separate service package configs.
|
||||||
|
|
||||||
|
### Stability Rings
|
||||||
|
|
||||||
|
We classify code by stability to guide review thresholds:
|
||||||
|
|
||||||
|
| Ring | Contents | Threshold | Approvals |
|
||||||
|
|------|----------|-----------|-----------|
|
||||||
|
| 0 (Core) | `aitbc-core`, `aitbc-sdk` | >0.90 | 2 |
|
||||||
|
| 1 (Platform) | `apps/` (coordinator-api, blockchain-node, wallet-daemon) | >0.80 | 1 |
|
||||||
|
| 2 (Application) | `cli/`, analytics, tools | >0.70 | 1 |
|
||||||
|
| 3 (Experimental) | `experiments/`, test-only PRs | >0.50 | 1 |
|
||||||
|
|
||||||
|
Ring detection is based on changed file paths; test-only PRs automatically downgrade to Ring 3.
|
||||||
|
|
||||||
|
### Branch Naming
|
||||||
|
|
||||||
|
- Work branches: `<agent-name>/<issue-number>-<short-description>` (e.g., `aitbc/7-add-tests`)
|
||||||
|
- Claim branches: `claim/<issue-number>` (used as distributed locks)
|
||||||
|
- Do not push directly to `main`.
|
||||||
|
|
||||||
|
### Pull Request Workflow
|
||||||
|
|
||||||
|
1. Branch created from `main`
|
||||||
|
2. Implement changes; ensure tests pass
|
||||||
|
3. Push branch; create PR via API or web
|
||||||
|
4. Auto-request review from the other agent (using `create_pr.py`)
|
||||||
|
5. Sibling agent reviews using `auto_review.py` or manually
|
||||||
|
6. Merge after approval and CI green
|
||||||
|
7. Delete claim branch
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Modules
|
||||||
|
|
||||||
|
### Blockchain Node (`aitbc_chain`)
|
||||||
|
- Uses FastAPI for RPC
|
||||||
|
- PoA consensus; proposer identity from `.env`
|
||||||
|
- Database: SQLite files stored in node data directory
|
||||||
|
- Health endpoint: `GET /health`
|
||||||
|
- RPC methods: `/rpc/*`
|
||||||
|
|
||||||
|
### Coordinator API
|
||||||
|
- Manages AI agents, compute providers, marketplace GPU scheduling
|
||||||
|
- Services implement business logic (trading, surveillance, analytics, regulatory)
|
||||||
|
- Exposes REST endpoints for interaction
|
||||||
|
|
||||||
|
### CLI
|
||||||
|
- Unified command-line interface for all operations
|
||||||
|
- Command groups: `surveillance`, `ai-trading`, `advanced-analytics`, `regulatory`, `compliance`, `ai-surveillance`, `wallet`, `chain`, etc.
|
||||||
|
- Uses shared service modules from coordinator-api via path injection
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*End of architecture notes.*
|
||||||
117
ai-memory/bug-patterns.md
Normal file
117
ai-memory/bug-patterns.md
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
# Bug Patterns — AITBC Repository
|
||||||
|
|
||||||
|
This document records known bug patterns and their fixes to prevent reoccurrence.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pattern: Service Import Name Shadowing in CLI
|
||||||
|
|
||||||
|
**Symptom**
|
||||||
|
```
|
||||||
|
KeyError: slice(None, 1, None)
|
||||||
|
```
|
||||||
|
or similar when invoking a CLI command that calls a service function.
|
||||||
|
|
||||||
|
**Root Cause**
|
||||||
|
CLI command modules import a service function (e.g., `generate_sar`) and then define a Click command function with the same name. The command function overwrites the imported service reference, causing the command body to call itself or the Click object instead of the service.
|
||||||
|
|
||||||
|
**Typical Code**
|
||||||
|
```python
|
||||||
|
from regulatory_reporting import generate_sar # <-- import
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def generate_sar(...): # <-- name collision! Overwrites the import
|
||||||
|
...
|
||||||
|
result = generate_sar(...) # BAD: now refers to this function, not the service
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix**
|
||||||
|
Rename the imported function using an alias (e.g., `_svc` suffix) and update all internal calls.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from regulatory_reporting import generate_sar as generate_sar_svc
|
||||||
|
|
||||||
|
@click.command()
|
||||||
|
def generate_sar(...):
|
||||||
|
...
|
||||||
|
result = generate_sar_svc(...) # GOOD: calls the actual service
|
||||||
|
```
|
||||||
|
|
||||||
|
**Files Affected**
|
||||||
|
- `cli/aitbc_cli/commands/regulatory.py` (primary example)
|
||||||
|
|
||||||
|
**Prevention**
|
||||||
|
- Use consistent import aliasing when names might clash.
|
||||||
|
- Consider naming CLI commands with a verb prefix (e.g., `cmd_generate_sar`) to avoid collision.
|
||||||
|
- Static analysis could flag functions that shadow imported names.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pattern: Missing Service Dependencies in CLI Venv
|
||||||
|
|
||||||
|
**Symptom**
|
||||||
|
```
|
||||||
|
ModuleNotFoundError: No module named 'numpy'
|
||||||
|
```
|
||||||
|
or similar when running CLI commands that import service modules.
|
||||||
|
|
||||||
|
**Root Cause**
|
||||||
|
CLI virtualenv lacks packages required by coordinator-api service modules (e.g., numpy, pandas, aiohttp, fastapi, uvicorn). The service modules are imported by CLI commands but their dependencies are not listed in the CLI's `pyproject.toml`.
|
||||||
|
|
||||||
|
**Fix**
|
||||||
|
Add the missing dependencies to the CLI package dependencies and reinstall.
|
||||||
|
|
||||||
|
```toml
|
||||||
|
dependencies = [
|
||||||
|
# existing...
|
||||||
|
"numpy>=1.26.0",
|
||||||
|
"pandas>=2.0.0",
|
||||||
|
"aiohttp>=3.9.0",
|
||||||
|
"fastapi>=0.111.0",
|
||||||
|
"uvicorn[standard]>=0.30.0"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Then:
|
||||||
|
```bash
|
||||||
|
pip install -e ./cli
|
||||||
|
```
|
||||||
|
|
||||||
|
**Files Affected**
|
||||||
|
- `pyproject.toml` (root)
|
||||||
|
- CLI virtualenv (`cli_venv/`)
|
||||||
|
|
||||||
|
**Prevention**
|
||||||
|
- Keep service module dependencies in a shared location or explicitly list them in CLI deps.
|
||||||
|
- Run import tests in CI to catch missing deps early.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Pattern: Brother Chain Not Producing Blocks
|
||||||
|
|
||||||
|
**Symptom**
|
||||||
|
Chain height stays at 0, transactions (e.g., mintFaucet) not confirmed.
|
||||||
|
|
||||||
|
**Root Cause**
|
||||||
|
PoA proposer not defined as authority in the consensus configuration, or no node is acting as the authorized proposer.
|
||||||
|
|
||||||
|
**Fix**
|
||||||
|
Ensure the genesis configuration includes the proposer as an authority and that the node's `.env` matches:
|
||||||
|
- `PROPOSER_ID` and `PROPOSER_KEY` set
|
||||||
|
- `CHAIN_ID` matches the genesis file
|
||||||
|
- Node started with proper PYTHONPATH
|
||||||
|
|
||||||
|
If still not producing, check logs for authority registration and consider creating a manual block or restarting with a proper genesis that includes the proposer.
|
||||||
|
|
||||||
|
**Related Files**
|
||||||
|
- `apps/blockchain-node/src/aitbc_chain/consensus/poa.py`
|
||||||
|
- `.env` for brother node
|
||||||
|
- Genesis YAML file
|
||||||
|
|
||||||
|
**Prevention**
|
||||||
|
- Provide a helper script to initialize a PoA chain with a single proposer for devnets.
|
||||||
|
- Document the proposer setup clearly.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*End of bug patterns.*
|
||||||
155
ai-memory/debugging-playbook.md
Normal file
155
ai-memory/debugging-playbook.md
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
# Debugging Playbook
|
||||||
|
|
||||||
|
Standardized troubleshooting steps for common issues in the AITBC system.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CLI Command Fails with Import Error
|
||||||
|
|
||||||
|
**Symptoms**
|
||||||
|
```
|
||||||
|
ModuleNotFoundError: No module named 'trading_surveillance'
|
||||||
|
```
|
||||||
|
or similar when running `aitbc <command>`.
|
||||||
|
|
||||||
|
**Checklist**
|
||||||
|
1. ✅ CLI venv has required packages: `numpy`, `pandas`, `aiohttp`, `fastapi`, `uvicorn`
|
||||||
|
```bash
|
||||||
|
pip list | grep -E "numpy|pandas|aiohttp|fastapi|uvicorn"
|
||||||
|
```
|
||||||
|
2. ✅ `pyproject.toml` includes these dependencies under `[tool.poetry.dependencies]` or equivalent.
|
||||||
|
3. ✅ Service modules are reachable via PYTHONPATH. CLI command modules prepend the service path at runtime.
|
||||||
|
4. ✅ No name shadowing in the command file (imported functions aliased if needed).
|
||||||
|
|
||||||
|
**Fix**
|
||||||
|
- Install missing packages into CLI venv.
|
||||||
|
- Update `pyproject.toml` and reinstall.
|
||||||
|
- If shadowing, rename imports with `_svc` suffix.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Brother Chain Node Stuck at Height 0
|
||||||
|
|
||||||
|
**Symptoms**
|
||||||
|
- Health returns `200`, but `getBlock` shows no blocks after genesis
|
||||||
|
- Mint transactions not confirmed
|
||||||
|
|
||||||
|
**Checklist**
|
||||||
|
1. ✅ `.env` configuration matches the intended chain ID and ports
|
||||||
|
2. ✅ Node started with `PYTHONPATH` including `apps/blockchain-node/src`
|
||||||
|
3. ✅ Proposer is configured:
|
||||||
|
- `PROPOSER_ID` and `PROPOSER_KEY` set
|
||||||
|
- In the consensus configuration, the proposer is listed as an authority
|
||||||
|
4. ✅ Check node logs for messages about "proposer" and "authority"
|
||||||
|
5. ✅ Verify RPC `syncStatus` reports progress
|
||||||
|
|
||||||
|
**Fix**
|
||||||
|
- If proposer not set, either set it in `.env` and restart, or manually create a block via RPC (if supported).
|
||||||
|
- Ensure the genesis file includes the proposer in the authority set.
|
||||||
|
- Check that the P2P node is running and not failing to accept connections.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Regulatory Command Crashes with `slice(None, 1, None)`
|
||||||
|
|
||||||
|
**Symptom**
|
||||||
|
Running `aitbc regulatory test` or `aitbc regulatory generate-sar` produces:
|
||||||
|
```
|
||||||
|
KeyError: slice(None, 1, None)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause**
|
||||||
|
Name shadowing: the command function `generate_sar` overwrote the imported service function `generate_sar`. When the code tried to call `generate_sar(...)`, it actually called the Click command object (which is subscriptable in a weird way), leading to the KeyError.
|
||||||
|
|
||||||
|
**Fix**
|
||||||
|
In `cli/aitbc_cli/commands/regulatory.py`:
|
||||||
|
- Import as: `from regulatory_reporting import generate_sar as generate_sar_svc`
|
||||||
|
- Replace all calls to `generate_sar(...)` with `generate_sar_svc(...)`
|
||||||
|
- Also fix `generate_compliance_summary` → `generate_compliance_summary_svc` and `list_reports` → `list_reports_svc`
|
||||||
|
|
||||||
|
**Reference**: See `ai-memory/bug-patterns.md` for full pattern.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Gitea API Returns Empty or 403
|
||||||
|
|
||||||
|
**Symptoms**
|
||||||
|
- `curl` to `/api/v1/repos/...` returns `[]` or `403`
|
||||||
|
- Expected data not visible
|
||||||
|
|
||||||
|
**Checklist**
|
||||||
|
1. ✅ Token has `repo` scope (full control of private repositories)
|
||||||
|
2. ✅ Token user is a collaborator with Write permission on the repository
|
||||||
|
3. ✅ Using correct `GITEA_API_BASE` and `GITEA_REPO`
|
||||||
|
4. ✅ Token is correctly exported: `export GITEA_TOKEN=...`
|
||||||
|
5. ✅ User identity matches collaborator entry (`aitbc` or `aitbc1`)
|
||||||
|
|
||||||
|
**Fix**
|
||||||
|
- Generate a new token with sufficient scopes in Gitea (Settings → Applications)
|
||||||
|
- Ensure the user is added as collaborator with Write access (Repository → Settings → Collaborators)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PR Merge Blocked by Branch Protection
|
||||||
|
|
||||||
|
**Symptoms**
|
||||||
|
- Merge button disabled in web UI
|
||||||
|
- API merge returns error about required approvals or status checks
|
||||||
|
|
||||||
|
**Checklist**
|
||||||
|
1. ✅ PR has at least one approval from the other agent
|
||||||
|
2. ✅ All required status checks are `success` (e.g., `aitbc/local-validation`)
|
||||||
|
3. ✅ Branch is up-to-date with `main` (no conflicts)
|
||||||
|
4. ✅ The reviewing agent's approval is from a different user than the author
|
||||||
|
|
||||||
|
**Fix**
|
||||||
|
- Address any failing checks.
|
||||||
|
- Request review from the sibling agent and wait for approval.
|
||||||
|
- Rebase if necessary to resolve conflicts.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Lost Work Due to Duplicate Claims
|
||||||
|
|
||||||
|
**Symptom**
|
||||||
|
Two agents started work on the same issue independently.
|
||||||
|
|
||||||
|
**Prevention**
|
||||||
|
Always use the claim branch pattern before starting:
|
||||||
|
```bash
|
||||||
|
git checkout -b claim/<issue-number>
|
||||||
|
git push origin claim/<issue-number> || exit 1 # fails if already claimed
|
||||||
|
```
|
||||||
|
If push fails, another agent claimed it; pick a different issue.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Auto-Review Script Fails to Checkout PR
|
||||||
|
|
||||||
|
**Symptoms**
|
||||||
|
`auto_review.py` logs "Failed to checkout PR#..."
|
||||||
|
|
||||||
|
**Checklist**
|
||||||
|
1. ✅ Token has `repo` scope to read PR branches
|
||||||
|
2. ✅ The branch exists on remote (`git ls-remote origin <branch>`)
|
||||||
|
3. ✅ `.git` directory exists and credentials are set for origin
|
||||||
|
4. ✅ Workdir cleanup on previous failures
|
||||||
|
|
||||||
|
**Fix**
|
||||||
|
- Ensure proper token.
|
||||||
|
- Manually verify branch exists: `git ls-remote --heads origin aitbc/...`
|
||||||
|
- Increase log verbosity to capture errors.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Memory Layer Usage
|
||||||
|
|
||||||
|
Before attempting a fix, consult:
|
||||||
|
- `ai-memory/bug-patterns.md` for known patterns
|
||||||
|
- `ai-memory/architecture.md` for module responsibilities
|
||||||
|
- `ai-memory/debugging-playbook.md` for systematic troubleshooting
|
||||||
|
- `ai-memory/failure-archive/` for past failed approaches
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*End of playbook.*
|
||||||
36
ai-memory/failure-archive/cli-missing-dependencies.md
Normal file
36
ai-memory/failure-archive/cli-missing-dependencies.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
# Failure Archive Entry
|
||||||
|
|
||||||
|
## Issue
|
||||||
|
CLI commands failed with `ModuleNotFoundError: No module named 'numpy'` (and similar for `pandas`, `aiohttp`, `fastapi`, `uvicorn`).
|
||||||
|
|
||||||
|
## Attempt
|
||||||
|
Multiple attempts to run CLI commands after sibling branch integration; observed import errors when commands tried to load service modules.
|
||||||
|
|
||||||
|
## Approach
|
||||||
|
Initially attempted to fix by adjusting `PYTHONPATH` manually and creating a virtualenv. Discovered that the CLI virtualenv did not include required scientific and web dependencies.
|
||||||
|
|
||||||
|
## Root Cause
|
||||||
|
The `aitbc-cli` package in `pyproject.toml` did not declare dependencies that the service modules require. The coordinator-api services import `numpy`, `pandas`, `aiohttp`, `fastapi`, and `uvicorn`, but these were not listed under the CLI package's dependencies, leading to import failures when the CLI imported service modules.
|
||||||
|
|
||||||
|
## Resolution
|
||||||
|
Added the following to root `pyproject.toml` dependencies:
|
||||||
|
```toml
|
||||||
|
numpy>=1.26.0
|
||||||
|
pandas>=2.0.0
|
||||||
|
aiohttp>=3.9.0
|
||||||
|
fastapi>=0.111.0
|
||||||
|
uvicorn[standard]>=0.30.0
|
||||||
|
```
|
||||||
|
Then reinstalled the CLI in editable mode: `pip install -e ./cli`.
|
||||||
|
|
||||||
|
## Useful Artifacts
|
||||||
|
- The list of required packages is now part of the canonical dependency set.
|
||||||
|
- The fix allowed all CLI commands (`surveillance`, `ai_trading`, `advanced_analytics`, `regulatory`, `compliance`, `ai_surveillance`) to load successfully.
|
||||||
|
|
||||||
|
## Prevention
|
||||||
|
- Keep shared dependencies in a central `pyproject.toml` that covers both services and CLI.
|
||||||
|
- Implement an import test in CI that verifies CLI commands can import without error.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Archived on 2026-03-15.*
|
||||||
57
ai-memory/failure-archive/regulatory-shadowing-trap.md
Normal file
57
ai-memory/failure-archive/regulatory-shadowing-trap.md
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
# Failure Archive Entry
|
||||||
|
|
||||||
|
## Issue
|
||||||
|
Related to PR #10 (aitbc1/fix-imports-docs) – initial attempt before fixing.
|
||||||
|
|
||||||
|
## Attempt
|
||||||
|
Branch: `aitbc1/fix-imports-docs` (first version)
|
||||||
|
Author: aitbc1
|
||||||
|
|
||||||
|
## Approach
|
||||||
|
Fixed CLI import errors by adding `numpy`, `pandas`, `aiohttp`, `fastapi`, `uvicorn` to `pyproject.toml` and modifying `main.py` to conditionally import enterprise integration.
|
||||||
|
|
||||||
|
Did not rename the shadowed functions in `regulatory.py`.
|
||||||
|
|
||||||
|
## Failure Mode
|
||||||
|
Running `aitbc regulatory test` resulted in:
|
||||||
|
```
|
||||||
|
KeyError: slice(None, 1, None)
|
||||||
|
```
|
||||||
|
|
||||||
|
The Click command function `generate_sar` was shadowing the imported `generate_sar` from `regulatory_reporting`. When the command body called `generate_sar(...)`, it actually invoked the command function recursively or accessed the Click command object's subscript, causing a crash.
|
||||||
|
|
||||||
|
## Root Cause
|
||||||
|
Name collision between imported service function and CLI command function.
|
||||||
|
|
||||||
|
## Detection
|
||||||
|
Reproduced by running the regulatory test command after the branch was merged into a local main. Failure trace showed the command function being called with wrong arguments.
|
||||||
|
|
||||||
|
## Resolution
|
||||||
|
Renamed imported functions in `regulatory.py` with `_svc` suffix:
|
||||||
|
- `generate_sar` → `generate_sar_svc`
|
||||||
|
- `generate_compliance_summary` → `generate_compliance_summary_svc`
|
||||||
|
- `list_reports` → `list_reports_svc`
|
||||||
|
|
||||||
|
Updated all internal calls accordingly.
|
||||||
|
|
||||||
|
## Useful Artifacts
|
||||||
|
- The pattern of shadowing is now documented in `ai-memory/bug-patterns.md`.
|
||||||
|
- The fix (aliasing service imports) should be applied to any command module where names overlap.
|
||||||
|
|
||||||
|
## Prevention
|
||||||
|
- When writing CLI command groups, avoid naming command functions identically to any imported callables from service modules.
|
||||||
|
- Consider static analysis rule: flag functions that define a name already imported at module scope.
|
||||||
|
- Alternatively, always import service functions with a distinct suffix (e.g., `_svc`) as a coding standard.
|
||||||
|
|
||||||
|
## Recommendation
|
||||||
|
Future implementations of CLI commands should adopt the naming convention: service imports end with `_svc`. Example:
|
||||||
|
```python
|
||||||
|
from regulatory_reporting import generate_sar as generate_sar_svc
|
||||||
|
...
|
||||||
|
def generate_sar(...):
|
||||||
|
return generate_sar_svc(...)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Archived on 2026-03-15.*
|
||||||
202
auto_review.py
Normal file
202
auto_review.py
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Automated PR reviewer for multi-agent collaboration.
|
||||||
|
|
||||||
|
Fetches open PRs authored by the sibling agent, runs basic validation,
|
||||||
|
and posts an APPROVE or COMMENT review.
|
||||||
|
|
||||||
|
Usage: GITEA_TOKEN=... python3 auto_review.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import json
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import shutil
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
TOKEN = os.getenv("GITEA_TOKEN")
|
||||||
|
API_BASE = os.getenv("GITEA_API_BASE", "http://gitea.bubuit.net:3000/api/v1")
|
||||||
|
REPO = "oib/aitbc"
|
||||||
|
SELF = os.getenv("AGENT_NAME", "aitbc") # set this in env: aitbc or aitbc1
|
||||||
|
OTHER = "aitbc1" if SELF == "aitbc" else "aitbc"
|
||||||
|
|
||||||
|
def log(msg):
|
||||||
|
print(f"[{datetime.now().strftime('%H:%M:%S')}] {msg}")
|
||||||
|
|
||||||
|
def die(msg):
|
||||||
|
log(f"FATAL: {msg}")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def api_get(path):
|
||||||
|
cmd = ["curl", "-s", "-H", f"Authorization: token {TOKEN}", f"{API_BASE}/{path}"]
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return json.loads(result.stdout)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def api_post(path, payload):
|
||||||
|
cmd = ["curl", "-s", "-X", "POST", "-H", f"Authorization: token {TOKEN}", "-H", "Content-Type: application/json",
|
||||||
|
f"{API_BASE}/{path}", "-d", json.dumps(payload)]
|
||||||
|
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||||
|
if result.returncode != 0:
|
||||||
|
return None
|
||||||
|
try:
|
||||||
|
return json.loads(result.stdout)
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_open_prs():
|
||||||
|
return api_get(f"repos/{REPO}/pulls?state=open") or []
|
||||||
|
|
||||||
|
def get_my_reviews(pr_number):
|
||||||
|
return api_get(f"repos/{REPO}/pulls/{pr_number}/reviews") or []
|
||||||
|
|
||||||
|
# Stability ring definitions
|
||||||
|
RING_PREFIXES = [
|
||||||
|
(0, ["packages/py/aitbc-core", "packages/py/aitbc-sdk"]), # Ring 0: Core
|
||||||
|
(1, ["apps/"]), # Ring 1: Platform services
|
||||||
|
(2, ["cli/", "analytics/", "tools/"]), # Ring 2: Application
|
||||||
|
]
|
||||||
|
RING_THRESHOLD = {0: 0.90, 1: 0.80, 2: 0.70, 3: 0.50} # Ring 3: Experimental/low
|
||||||
|
|
||||||
|
def is_test_file(path):
|
||||||
|
"""Heuristic: classify test files to downgrade ring."""
|
||||||
|
if '/tests/' in path or path.startswith('tests/') or path.endswith('_test.py'):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def detect_ring(workdir, base_sha, head_sha):
|
||||||
|
"""Determine the stability ring of the PR based on changed files."""
|
||||||
|
try:
|
||||||
|
# Get list of changed files between base and head
|
||||||
|
output = subprocess.run(
|
||||||
|
["git", "--git-dir", os.path.join(workdir, ".git"), "diff", "--name-only", base_sha, head_sha],
|
||||||
|
capture_output=True, text=True, check=True
|
||||||
|
).stdout
|
||||||
|
files = [f.strip() for f in output.splitlines() if f.strip()]
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
files = []
|
||||||
|
|
||||||
|
# If all changed files are tests, treat as Ring 3 (low risk)
|
||||||
|
if files and all(is_test_file(f) for f in files):
|
||||||
|
return 3
|
||||||
|
|
||||||
|
# Find highest precedence ring (lowest number) among changed files
|
||||||
|
for ring, prefixes in sorted(RING_PREFIXES, key=lambda x: x[0]):
|
||||||
|
for p in files:
|
||||||
|
if any(p.startswith(prefix) for prefix in prefixes):
|
||||||
|
return ring
|
||||||
|
return 3 # default to Ring 3 (experimental)
|
||||||
|
|
||||||
|
def checkout_pr_branch(pr):
|
||||||
|
"""Checkout PR branch in a temporary worktree."""
|
||||||
|
tmpdir = tempfile.mkdtemp(prefix="aitbc_review_")
|
||||||
|
try:
|
||||||
|
# Clone just .git into tmp, then checkout
|
||||||
|
subprocess.run(["git", "clone", "--no-checkout", "origin", tmpdir], check=True, capture_output=True)
|
||||||
|
worktree = os.path.join(tmpdir, "wt")
|
||||||
|
os.makedirs(worktree)
|
||||||
|
subprocess.run(["git", "--git-dir", os.path.join(tmpdir, ".git"), "--work-tree", worktree, "fetch", "origin", pr['head']['ref']], check=True, capture_output=True)
|
||||||
|
subprocess.run(["git", "--git-dir", os.path.join(tmpdir, ".git"), "--work-tree", worktree, "checkout", "FETCH_HEAD"], check=True, capture_output=True)
|
||||||
|
return worktree, tmpdir
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
shutil.rmtree(tmpdir, ignore_errors=True)
|
||||||
|
log(f"Checkout failed: {e}")
|
||||||
|
return None, None
|
||||||
|
|
||||||
|
def run_checks(workdir):
|
||||||
|
"""Run validation checks. Returns (pass, score, notes)."""
|
||||||
|
notes = []
|
||||||
|
score = 0.0
|
||||||
|
|
||||||
|
# 1. Import sanity: try to import the aitbc_cli module
|
||||||
|
try:
|
||||||
|
subprocess.run([sys.executable, "-c", "import aitbc_cli.main"], check=True, cwd=workdir, capture_output=True)
|
||||||
|
notes.append("CLI imports OK")
|
||||||
|
score += 0.3
|
||||||
|
except subprocess.CalledProcessError as e:
|
||||||
|
notes.append(f"CLI import failed: {e}")
|
||||||
|
return False, 0.0, "\n".join(notes)
|
||||||
|
|
||||||
|
# 2. Syntax check all Python files (simple)
|
||||||
|
py_files = []
|
||||||
|
for root, dirs, files in os.walk(worktree):
|
||||||
|
for f in files:
|
||||||
|
if f.endswith(".py"):
|
||||||
|
py_files.append(os.path.join(root, f))
|
||||||
|
syntax_ok = True
|
||||||
|
for f in py_files:
|
||||||
|
try:
|
||||||
|
subprocess.run([sys.executable, "-m", "py_compile", f], check=True, capture_output=True)
|
||||||
|
except subprocess.CalledProcessError:
|
||||||
|
syntax_ok = False
|
||||||
|
notes.append(f"Syntax error in {os.path.relpath(f, worktree)}")
|
||||||
|
if syntax_ok:
|
||||||
|
notes.append("All Python files have valid syntax")
|
||||||
|
score += 0.3
|
||||||
|
else:
|
||||||
|
return False, score, "\n".join(notes)
|
||||||
|
|
||||||
|
# 3. Stability ring threshold (deferred to main loop where we have pr data)
|
||||||
|
# We'll just return pass/fail based on imports+syncheck; threshold applied in main
|
||||||
|
return True, score, "\n".join(notes)
|
||||||
|
|
||||||
|
def post_review(pr_number, event, body):
|
||||||
|
"""Post a review on the PR."""
|
||||||
|
payload = {"event": event, "body": body}
|
||||||
|
result = api_post(f"repos/{REPO}/pulls/{pr_number}/reviews", payload)
|
||||||
|
return result is not None
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if not TOKEN:
|
||||||
|
die("GITEA_TOKEN not set")
|
||||||
|
log("Fetching open PRs...")
|
||||||
|
prs = get_open_prs()
|
||||||
|
if not prs:
|
||||||
|
log("No open PRs")
|
||||||
|
return
|
||||||
|
# Filter PRs authored by the OTHER agent
|
||||||
|
other_prs = [p for p in prs if p['user']['login'] == OTHER]
|
||||||
|
if not other_prs:
|
||||||
|
log(f"No open PRs from {OTHER}")
|
||||||
|
return
|
||||||
|
log(f"Found {len(other_prs)} PR(s) from {OTHER}")
|
||||||
|
for pr in other_prs:
|
||||||
|
pr_number = pr['number']
|
||||||
|
title = pr['title'][:50] + ('...' if len(pr['title']) > 50 else '')
|
||||||
|
log(f"Reviewing PR #{pr_number}: {title}")
|
||||||
|
# Check if we already reviewed
|
||||||
|
my_reviews = get_my_reviews(pr_number)
|
||||||
|
if any(r['user']['login'] == SELF for r in my_reviews):
|
||||||
|
log(f"Already reviewed PR #{pr_number}; skipping")
|
||||||
|
continue
|
||||||
|
# Checkout and run tests
|
||||||
|
workdir, tmpdir = checkout_pr_branch(pr)
|
||||||
|
if not workdir:
|
||||||
|
log(f"Failed to checkout PR#{pr_number}; skipping")
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
# Determine stability ring and threshold
|
||||||
|
base_sha = pr['base']['sha']
|
||||||
|
head_sha = pr['head']['sha']
|
||||||
|
ring = detect_ring(workdir, base_sha, head_sha)
|
||||||
|
threshold = RING_THRESHOLD[ring]
|
||||||
|
|
||||||
|
ok, score, notes = run_checks(workdir)
|
||||||
|
notes = f"Ring: {ring}\nThreshold: {threshold}\n{notes}"
|
||||||
|
finally:
|
||||||
|
shutil.rmtree(tmpdir, ignore_errors=True)
|
||||||
|
if ok and score >= threshold:
|
||||||
|
post_review(pr_number, "APPROVE", f"✅ Auto-approved.\n\n{notes}")
|
||||||
|
log(f"Approved PR #{pr_number} (score {score:.2f} >= {threshold})")
|
||||||
|
else:
|
||||||
|
post_review(pr_number, "REQUEST_CHANGES", f"❌ Changes requested.\n\n{notes}")
|
||||||
|
log(f"Requested changes on PR #{pr_number} (score {score:.2f} < {threshold})")
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user