feat(system): chore: gitignore HERALD.md and remove from README

Co-Authored-By: @devpulse <devpulse@aipass>
This commit is contained in:
AIOSAI
2026-04-22 23:07:56 -07:00
co-authored by @devpulse
parent 4413df63ea
commit f0019ca204
6 changed files with 119 additions and 4 deletions
+3
View File
@@ -1,6 +1,9 @@
# Virtual environment
.venv/
# Herald (session history — parked)
HERALD.md
# Python
__pycache__/
*.pyc
+1 -3
View File
@@ -1,4 +1,4 @@
[![Status](https://img.shields.io/badge/status-beta-yellow)](HERALD.md)
[![Status](https://img.shields.io/badge/status-beta-yellow)](#project-status)
[![Python 3.10+](https://img.shields.io/badge/python-3.10%2B-blue)](pyproject.toml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green)](LICENSE)
[![PyPI](https://img.shields.io/pypi/v/aipass)](https://pypi.org/project/aipass/)
@@ -232,8 +232,6 @@ setup.sh auto-detects which CLIs are installed and configures hooks for each.
Each agent documents its own operational status in its branch README — what works, what doesn't, and why.
For detailed session history, see [HERALD.md](HERALD.md).
---
## Requirements
@@ -34,6 +34,7 @@ from aipass.spawn.apps.handlers.registry import (
find_registry,
add_to_registry,
get_next_citizen_number,
ensure_project_has_owner,
)
from aipass.spawn.apps.handlers.class_registry import get_template_dir
from aipass.spawn.apps.handlers.json import json_handler
@@ -124,6 +125,9 @@ def grant_passport(
purpose or "Birthright citizen - purpose TBD",
)
# Ensure at least one agent in the project is the owner
ensure_project_has_owner(reg_path)
# Validate
issues = validate_no_placeholders(target)
@@ -265,3 +265,34 @@ def fix_passport_registry_id(branch_dir: Path, registry_path: Path) -> bool:
except Exception as e:
logger.warning("[registry] Failed to fix registry_id for %s: %s", branch_dir.name, e)
return False
def ensure_project_has_owner(registry_path):
"""If no agent in the project has owner:true, assign it to the earliest-created agent."""
registry_path = Path(registry_path)
reg_data = load_registry(registry_path)
branches = _branches_as_list(reg_data.get("branches", []))
if not branches:
return False
registry_root = registry_path.parent
for branch in branches:
branch_path = registry_root / branch.get("path", "")
passport_path = branch_path / ".trinity" / "passport.json"
if passport_path.exists():
passport = json_handler.read_json(passport_path)
if passport and passport.get("citizenship", {}).get("owner") is True:
return False
by_created = sorted(branches, key=lambda b: b.get("created", "9999-99-99"))
for branch in by_created:
branch_path = registry_root / branch.get("path", "")
passport_path = branch_path / ".trinity" / "passport.json"
if passport_path.exists():
passport = json_handler.read_json(passport_path)
if passport:
passport.setdefault("citizenship", {})["owner"] = True
json_handler.write_json(passport_path, passport)
logger.info("[registry] Retroactively set owner=true on %s", branch.get("name", "?"))
return True
return False
+5 -1
View File
@@ -46,6 +46,7 @@ from aipass.spawn.apps.handlers.registry import (
add_to_registry,
get_next_citizen_number,
fix_passport_registry_id,
ensure_project_has_owner,
)
from aipass.spawn.apps.handlers.class_registry import (
get_template_dir as _get_template_dir,
@@ -250,7 +251,10 @@ def _spawn_agent(
purpose or "New agent - purpose TBD",
)
# Step 5: Validate no unreplaced placeholders
# Step 5: Ensure at least one agent in the project is the owner
ensure_project_has_owner(reg_path)
# Step 6: Validate no unreplaced placeholders
issues = validate_no_placeholders(target)
json_handler.log_operation("branch_created", data={"branch": branch_upper})
@@ -531,3 +531,78 @@ class TestPassportOwnerField:
p2 = json.loads((second / ".trinity" / "passport.json").read_text())
assert p1["citizenship"]["owner"] is True
assert p2["citizenship"]["owner"] is False
class TestRetroactiveOwner:
"""Tests for retroactive owner assignment on legacy projects."""
def test_retroactive_owner_on_legacy_agents(self, tmp_path):
"""Creating a new agent in a project where no agent has owner sets the first one."""
from aipass.spawn.apps.modules.core import _spawn_agent
reg = tmp_path / "TEST_REGISTRY.json"
reg.write_text('{"metadata":{"version":"1.0.0","total_branches":0},"branches":[]}')
# Create two agents, then remove their owner field to simulate legacy
_spawn_agent(str(tmp_path / "old_a"), registry_path=str(reg))
_spawn_agent(str(tmp_path / "old_b"), registry_path=str(reg))
for name in ["old_a", "old_b"]:
pp = tmp_path / name / ".trinity" / "passport.json"
data = json.loads(pp.read_text())
del data["citizenship"]["owner"]
pp.write_text(json.dumps(data, indent=2))
# Create a third agent — should trigger retroactive fix
_spawn_agent(str(tmp_path / "new_c"), registry_path=str(reg))
pa = json.loads((tmp_path / "old_a" / ".trinity" / "passport.json").read_text())
pb = json.loads((tmp_path / "old_b" / ".trinity" / "passport.json").read_text())
pc = json.loads((tmp_path / "new_c" / ".trinity" / "passport.json").read_text())
assert pa["citizenship"]["owner"] is True
assert pb["citizenship"].get("owner") is not True
assert pc["citizenship"]["owner"] is False
def test_no_retroactive_if_owner_exists(self, tmp_path):
"""If an existing agent already has owner:true, no retroactive change."""
from aipass.spawn.apps.modules.core import _spawn_agent
reg = tmp_path / "TEST_REGISTRY.json"
reg.write_text('{"metadata":{"version":"1.0.0","total_branches":0},"branches":[]}')
_spawn_agent(str(tmp_path / "first"), registry_path=str(reg))
_spawn_agent(str(tmp_path / "second"), registry_path=str(reg))
_spawn_agent(str(tmp_path / "third"), registry_path=str(reg))
p1 = json.loads((tmp_path / "first" / ".trinity" / "passport.json").read_text())
p2 = json.loads((tmp_path / "second" / ".trinity" / "passport.json").read_text())
p3 = json.loads((tmp_path / "third" / ".trinity" / "passport.json").read_text())
assert p1["citizenship"]["owner"] is True
assert p2["citizenship"]["owner"] is False
assert p3["citizenship"]["owner"] is False
def test_ensure_project_has_owner_direct(self, tmp_path):
"""Direct call to ensure_project_has_owner fixes a legacy project."""
from aipass.spawn.apps.handlers.registry import ensure_project_has_owner
from aipass.spawn.apps.modules.core import _spawn_agent
reg = tmp_path / "TEST_REGISTRY.json"
reg.write_text('{"metadata":{"version":"1.0.0","total_branches":0},"branches":[]}')
_spawn_agent(str(tmp_path / "agent_x"), registry_path=str(reg))
_spawn_agent(str(tmp_path / "agent_y"), registry_path=str(reg))
# Strip owner from both
for name in ["agent_x", "agent_y"]:
pp = tmp_path / name / ".trinity" / "passport.json"
data = json.loads(pp.read_text())
data["citizenship"].pop("owner", None)
pp.write_text(json.dumps(data, indent=2))
result = ensure_project_has_owner(reg)
assert result is True
px = json.loads((tmp_path / "agent_x" / ".trinity" / "passport.json").read_text())
py = json.loads((tmp_path / "agent_y" / ".trinity" / "passport.json").read_text())
assert px["citizenship"]["owner"] is True
assert py["citizenship"].get("owner") is not True