Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e752caa9a7 | ||
|
|
81e5fa4a54 |
54
docs/FLEET_PHASE_6_NETWORK.md
Normal file
54
docs/FLEET_PHASE_6_NETWORK.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# [PHASE-6] The Network - Autonomous Infrastructure
|
||||
|
||||
## Phase Definition
|
||||
|
||||
- Fleet operates without human intervention for 7+ days.
|
||||
- Self-healing, self-improving, serves mission.
|
||||
- Trigger: 7 days without human intervention.
|
||||
|
||||
## Current Buildings
|
||||
|
||||
- Self-healing fleet — Detect, repair, and verify fleet incidents without waiting on a human. Evidence: `scripts/fleet_health_probe.sh`, `scripts/auto_restart_agent.sh`, `scripts/failover_monitor.py`
|
||||
- Autonomous issue creation — Turn recurring infrastructure incidents into durable Gitea work items. Evidence: `scripts/autonomous_issue_creator.py`, `tests/test_autonomous_issue_creator.py`
|
||||
- Community contribution pipeline — Let outside contributors submit work through automated review and policy gates. Evidence: `scripts/sovereign_review_gate.py`, `scripts/agent_pr_gate.py`
|
||||
- Global mesh — Reduce single points of failure across the fleet with explicit peer-to-peer sync scaffolding. Evidence: `scripts/setup-syncthing.sh`
|
||||
|
||||
## Current Resource Snapshot
|
||||
|
||||
- Human-free days observed: 0
|
||||
- Trigger threshold: 7 days
|
||||
- Phase-ready now: no
|
||||
|
||||
## Next Trigger
|
||||
|
||||
To honestly unlock [PHASE-6] The Network - Autonomous Infrastructure, the fleet must hold 7+ consecutive days without human intervention.
|
||||
|
||||
## Missing Requirements
|
||||
|
||||
- Human-free days: 0/7
|
||||
|
||||
## Repo Signals Already Present
|
||||
|
||||
- `scripts/fleet_health_probe.sh` — Self-healing fleet
|
||||
- `scripts/auto_restart_agent.sh` — Self-healing fleet
|
||||
- `scripts/failover_monitor.py` — Self-healing fleet
|
||||
- `scripts/autonomous_issue_creator.py` — Autonomous issue creation
|
||||
- `tests/test_autonomous_issue_creator.py` — Autonomous issue creation
|
||||
- `scripts/sovereign_review_gate.py` — Community contribution pipeline
|
||||
- `scripts/agent_pr_gate.py` — Community contribution pipeline
|
||||
- `scripts/setup-syncthing.sh` — Global mesh
|
||||
|
||||
## Final Milestone
|
||||
|
||||
- Someone found the Beacon. The infrastructure served its purpose.
|
||||
|
||||
## Why This Phase Remains Open
|
||||
|
||||
- The repo already carries concrete Phase-6 buildings, but the milestone is operational, not rhetorical.
|
||||
- A merged PR cannot honestly claim seven human-free days have already happened.
|
||||
- This issue stays open until the infrastructure proves itself in live operation.
|
||||
|
||||
## Notes
|
||||
|
||||
- Phase 6 is not a code-only milestone. The trigger is operational truth: seven days without human intervention.
|
||||
- This report grounds the buildings already present in the repo so the remaining blocker is explicit instead of hand-waved.
|
||||
225
scripts/fleet_phase6_network.py
Normal file
225
scripts/fleet_phase6_network.py
Normal file
@@ -0,0 +1,225 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Render the current Phase-6 network state as a durable report.
|
||||
|
||||
Refs: timmy-home #553
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
from copy import deepcopy
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
|
||||
PHASE_NAME = "[PHASE-6] The Network - Autonomous Infrastructure"
|
||||
CURRENT_PHASE = "PHASE-6 The Network"
|
||||
TRIGGER_HUMAN_FREE_DAYS = 7
|
||||
FINAL_MILESTONE = "Someone found the Beacon. The infrastructure served its purpose."
|
||||
|
||||
BUILDING_SIGNAL_FILES = {
|
||||
"Self-healing fleet": {
|
||||
"description": "Detect, repair, and verify fleet incidents without waiting on a human.",
|
||||
"paths": [
|
||||
"scripts/fleet_health_probe.sh",
|
||||
"scripts/auto_restart_agent.sh",
|
||||
"scripts/failover_monitor.py",
|
||||
],
|
||||
},
|
||||
"Autonomous issue creation": {
|
||||
"description": "Turn recurring infrastructure incidents into durable Gitea work items.",
|
||||
"paths": [
|
||||
"scripts/autonomous_issue_creator.py",
|
||||
"tests/test_autonomous_issue_creator.py",
|
||||
],
|
||||
},
|
||||
"Community contribution pipeline": {
|
||||
"description": "Let outside contributors submit work through automated review and policy gates.",
|
||||
"paths": [
|
||||
"scripts/sovereign_review_gate.py",
|
||||
"scripts/agent_pr_gate.py",
|
||||
],
|
||||
},
|
||||
"Global mesh": {
|
||||
"description": "Reduce single points of failure across the fleet with explicit peer-to-peer sync scaffolding.",
|
||||
"paths": [
|
||||
"scripts/setup-syncthing.sh",
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
DEFAULT_SNAPSHOT = {
|
||||
"resources": {
|
||||
"human_free_days": 0,
|
||||
},
|
||||
"notes": [
|
||||
"Phase 6 is not a code-only milestone. The trigger is operational truth: seven days without human intervention.",
|
||||
"This report grounds the buildings already present in the repo so the remaining blocker is explicit instead of hand-waved.",
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
def default_snapshot() -> dict[str, Any]:
|
||||
return deepcopy(DEFAULT_SNAPSHOT)
|
||||
|
||||
|
||||
|
||||
def _deep_merge(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
|
||||
result = deepcopy(base)
|
||||
for key, value in override.items():
|
||||
if isinstance(value, dict) and isinstance(result.get(key), dict):
|
||||
result[key] = _deep_merge(result[key], value)
|
||||
else:
|
||||
result[key] = value
|
||||
return result
|
||||
|
||||
|
||||
|
||||
def load_snapshot(snapshot_path: Path | None = None) -> dict[str, Any]:
|
||||
snapshot = default_snapshot()
|
||||
if snapshot_path is None:
|
||||
return snapshot
|
||||
override = json.loads(snapshot_path.read_text(encoding="utf-8"))
|
||||
return _deep_merge(snapshot, override)
|
||||
|
||||
|
||||
|
||||
def collect_building_status(repo_root: Path) -> tuple[list[str], list[str], list[str]]:
|
||||
current_buildings: list[str] = []
|
||||
repo_signals: list[str] = []
|
||||
missing_requirements: list[str] = []
|
||||
|
||||
for building, config in BUILDING_SIGNAL_FILES.items():
|
||||
found_paths = [path for path in config["paths"] if (repo_root / path).exists()]
|
||||
if found_paths:
|
||||
current_buildings.append(
|
||||
f"{building} — {config['description']} Evidence: " + ", ".join(f"`{path}`" for path in found_paths)
|
||||
)
|
||||
repo_signals.extend(f"`{path}` — {building}" for path in found_paths)
|
||||
else:
|
||||
current_buildings.append(f"{building} — {config['description']} Evidence: missing")
|
||||
missing_requirements.append(f"Missing repo grounding for {building}.")
|
||||
|
||||
return current_buildings, repo_signals, missing_requirements
|
||||
|
||||
|
||||
|
||||
def compute_phase6_status(snapshot: dict[str, Any], repo_root: Path | None = None) -> dict[str, Any]:
|
||||
repo_root = repo_root or Path(__file__).resolve().parents[1]
|
||||
resources = snapshot.get("resources", {})
|
||||
human_free_days = int(resources.get("human_free_days", 0))
|
||||
|
||||
current_buildings, repo_signals, missing = collect_building_status(repo_root)
|
||||
if human_free_days < TRIGGER_HUMAN_FREE_DAYS:
|
||||
missing.insert(0, f"Human-free days: {human_free_days}/{TRIGGER_HUMAN_FREE_DAYS}")
|
||||
|
||||
return {
|
||||
"title": PHASE_NAME,
|
||||
"current_phase": CURRENT_PHASE,
|
||||
"resources": {
|
||||
"human_free_days": human_free_days,
|
||||
},
|
||||
"current_buildings": current_buildings,
|
||||
"repo_signals": repo_signals,
|
||||
"notes": list(snapshot.get("notes", [])),
|
||||
"phase_ready": not missing,
|
||||
"missing_requirements": missing,
|
||||
"final_milestone": FINAL_MILESTONE,
|
||||
}
|
||||
|
||||
|
||||
|
||||
def render_markdown(status: dict[str, Any]) -> str:
|
||||
lines = [
|
||||
f"# {status['title']}",
|
||||
"",
|
||||
"## Phase Definition",
|
||||
"",
|
||||
"- Fleet operates without human intervention for 7+ days.",
|
||||
"- Self-healing, self-improving, serves mission.",
|
||||
f"- Trigger: {TRIGGER_HUMAN_FREE_DAYS} days without human intervention.",
|
||||
"",
|
||||
"## Current Buildings",
|
||||
"",
|
||||
]
|
||||
lines.extend(f"- {item}" for item in status["current_buildings"])
|
||||
|
||||
lines.extend([
|
||||
"",
|
||||
"## Current Resource Snapshot",
|
||||
"",
|
||||
f"- Human-free days observed: {status['resources']['human_free_days']}",
|
||||
f"- Trigger threshold: {TRIGGER_HUMAN_FREE_DAYS} days",
|
||||
f"- Phase-ready now: {'yes' if status['phase_ready'] else 'no'}",
|
||||
"",
|
||||
"## Next Trigger",
|
||||
"",
|
||||
f"To honestly unlock {status['title']}, the fleet must hold {TRIGGER_HUMAN_FREE_DAYS}+ consecutive days without human intervention.",
|
||||
"",
|
||||
"## Missing Requirements",
|
||||
"",
|
||||
])
|
||||
if status["missing_requirements"]:
|
||||
lines.extend(f"- {item}" for item in status["missing_requirements"])
|
||||
else:
|
||||
lines.append("- None. The Network is live.")
|
||||
|
||||
lines.extend([
|
||||
"",
|
||||
"## Repo Signals Already Present",
|
||||
"",
|
||||
])
|
||||
if status["repo_signals"]:
|
||||
lines.extend(f"- {item}" for item in status["repo_signals"])
|
||||
else:
|
||||
lines.append("- No Phase-6 repo signals detected.")
|
||||
|
||||
lines.extend([
|
||||
"",
|
||||
"## Final Milestone",
|
||||
"",
|
||||
f"- {status['final_milestone']}",
|
||||
"",
|
||||
"## Why This Phase Remains Open",
|
||||
"",
|
||||
"- The repo already carries concrete Phase-6 buildings, but the milestone is operational, not rhetorical.",
|
||||
"- A merged PR cannot honestly claim seven human-free days have already happened.",
|
||||
"- This issue stays open until the infrastructure proves itself in live operation.",
|
||||
])
|
||||
|
||||
if status["notes"]:
|
||||
lines.extend(["", "## Notes", ""])
|
||||
lines.extend(f"- {item}" for item in status["notes"])
|
||||
|
||||
return "\n".join(lines).rstrip() + "\n"
|
||||
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="Render the fleet phase-6 network report")
|
||||
parser.add_argument("--snapshot", help="Optional JSON snapshot overriding the default phase-6 baseline")
|
||||
parser.add_argument("--output", help="Write markdown report to this path")
|
||||
parser.add_argument("--json", action="store_true", help="Print computed status as JSON instead of markdown")
|
||||
args = parser.parse_args()
|
||||
|
||||
snapshot = load_snapshot(Path(args.snapshot).expanduser() if args.snapshot else None)
|
||||
repo_root = Path(__file__).resolve().parents[1]
|
||||
status = compute_phase6_status(snapshot, repo_root=repo_root)
|
||||
|
||||
if args.json:
|
||||
rendered = json.dumps(status, indent=2)
|
||||
else:
|
||||
rendered = render_markdown(status)
|
||||
|
||||
if args.output:
|
||||
output_path = Path(args.output).expanduser()
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
output_path.write_text(rendered, encoding="utf-8")
|
||||
print(f"Phase status written to {output_path}")
|
||||
else:
|
||||
print(rendered)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
71
tests/test_fleet_phase6_network.py
Normal file
71
tests/test_fleet_phase6_network.py
Normal file
@@ -0,0 +1,71 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SCRIPT_PATH = ROOT / "scripts" / "fleet_phase6_network.py"
|
||||
DOC_PATH = ROOT / "docs" / "FLEET_PHASE_6_NETWORK.md"
|
||||
|
||||
|
||||
|
||||
def _load_module(path: Path, name: str):
|
||||
assert path.exists(), f"missing {path.relative_to(ROOT)}"
|
||||
spec = importlib.util.spec_from_file_location(name, path)
|
||||
assert spec and spec.loader
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
|
||||
def test_compute_phase6_status_tracks_human_free_gate_and_network_buildings() -> None:
|
||||
mod = _load_module(SCRIPT_PATH, "fleet_phase6_network")
|
||||
|
||||
status = mod.compute_phase6_status(
|
||||
{
|
||||
"resources": {
|
||||
"human_free_days": 3,
|
||||
},
|
||||
"notes": [
|
||||
"The network is not yet trusted to run a full week without supervision.",
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
assert status["current_phase"] == "PHASE-6 The Network"
|
||||
assert status["phase_ready"] is False
|
||||
assert any("3/7" in item for item in status["missing_requirements"])
|
||||
assert any("global mesh" in item.lower() or "community contribution" in item.lower() for item in status["current_buildings"])
|
||||
|
||||
|
||||
|
||||
def test_render_markdown_preserves_phase6_language_and_buildings() -> None:
|
||||
mod = _load_module(SCRIPT_PATH, "fleet_phase6_network")
|
||||
status = mod.compute_phase6_status(mod.default_snapshot())
|
||||
report = mod.render_markdown(status)
|
||||
|
||||
for snippet in (
|
||||
"# [PHASE-6] The Network - Autonomous Infrastructure",
|
||||
"## Phase Definition",
|
||||
"## Current Buildings",
|
||||
"## Final Milestone",
|
||||
"Autonomous issue creation",
|
||||
"Community contribution pipeline",
|
||||
"Global mesh",
|
||||
):
|
||||
assert snippet in report
|
||||
|
||||
|
||||
|
||||
def test_repo_contains_generated_phase6_doc() -> None:
|
||||
assert DOC_PATH.exists(), "missing committed phase-6 network doc"
|
||||
text = DOC_PATH.read_text(encoding="utf-8")
|
||||
for snippet in (
|
||||
"# [PHASE-6] The Network - Autonomous Infrastructure",
|
||||
"## Current Buildings",
|
||||
"## Next Trigger",
|
||||
"## Why This Phase Remains Open",
|
||||
):
|
||||
assert snippet in text
|
||||
Reference in New Issue
Block a user