From 8274edffebb31c97f9f979a9596ba2e3e69382ab Mon Sep 17 00:00:00 2001 From: Svrnty Date: Sun, 14 Jun 2026 08:40:58 -0400 Subject: [PATCH] docs: capture personal-agent runtime readiness snapshot --- README.md | 1 + WORKBOARD.yaml | 5 + docs/STEEV-MASTER.md | 1 + ...onal-agent-runtime-readiness-snapshot.json | 170 ++++++++++++++++++ ...t-context-runtime-supersession-register.md | 2 + tools/validate_steev_child.py | 137 +++++++++++++- 6 files changed, 315 insertions(+), 1 deletion(-) create mode 100644 docs/contracts/personal-agent-runtime-readiness-snapshot.json diff --git a/README.md b/README.md index 246ad81..3ecf6be 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ JP's personal assistant / chief of staff. Daily briefing, inbox triage, comms in - **Proton/rclone package candidate:** [`docs/contracts/personal-agent-proton-rclone-package.json`](docs/contracts/personal-agent-proton-rclone-package.json) — Mail, Calendar, Contacts, and Drive surfaces with redacted runtime inventory and no readiness overclaim. - **Secondbrain proposal route:** [`docs/contracts/personal-agent-secondbrain-proposal-route.json`](docs/contracts/personal-agent-secondbrain-proposal-route.json) — proposal-only personal memory intake; durable apply remains owned by Secondbrain. - **Conductor/Curator service handoff:** [`docs/contracts/personal-agent-conductor-curator-service-handoff.json`](docs/contracts/personal-agent-conductor-curator-service-handoff.json) — redacted service map for future route selection and hygiene review pickup. +- **Runtime readiness snapshot:** [`docs/contracts/personal-agent-runtime-readiness-snapshot.json`](docs/contracts/personal-agent-runtime-readiness-snapshot.json) — redacted per-surface runtime state and gaps; aggregate readiness remains degraded. - **Historical Steev reference redirect:** [`docs/STEEV-MASTER.md`](docs/STEEV-MASTER.md). ## Structure diff --git a/WORKBOARD.yaml b/WORKBOARD.yaml index 5774763..b171326 100644 --- a/WORKBOARD.yaml +++ b/WORKBOARD.yaml @@ -39,3 +39,8 @@ items: status: complete source: docs/contracts/personal-agent-conductor-curator-service-handoff.json owner: jp + - id: PACR-007 + title: Runtime Readiness And Always-On Proof + status: complete + source: docs/contracts/personal-agent-runtime-readiness-snapshot.json + owner: jp diff --git a/docs/STEEV-MASTER.md b/docs/STEEV-MASTER.md index c2efde0..6186753 100644 --- a/docs/STEEV-MASTER.md +++ b/docs/STEEV-MASTER.md @@ -18,6 +18,7 @@ Active authority: - `docs/contracts/personal-agent-proton-rclone-package.json` - `docs/contracts/personal-agent-secondbrain-proposal-route.json` - `docs/contracts/personal-agent-conductor-curator-service-handoff.json` +- `docs/contracts/personal-agent-runtime-readiness-snapshot.json` - `docs/prd/2026-06-14-personal-agent-context-runtime-prd.md` - `docs/supersession/2026-06-14-personal-agent-context-runtime-supersession-register.md` diff --git a/docs/contracts/personal-agent-runtime-readiness-snapshot.json b/docs/contracts/personal-agent-runtime-readiness-snapshot.json new file mode 100644 index 0000000..ee9a0b2 --- /dev/null +++ b/docs/contracts/personal-agent-runtime-readiness-snapshot.json @@ -0,0 +1,170 @@ +{ + "schema_version": "personal-agent-runtime-readiness-snapshot/v1", + "status": "active-redacted-runtime-snapshot", + "snapshot_id": "personal-agent-runtime-readiness-2026-06-14", + "profile_identity": "personal-agent", + "display_name": "Steev", + "observed_date": "2026-06-14", + "aggregate_runtime_state": "degraded", + "runtime_readiness_claimed": false, + "seed_readiness_claimed": false, + "core_promotion_claimed": false, + "memory_target": "secondbrain-personal", + "forbidden_memory_targets": [ + "orgbrain" + ], + "surface_states": [ + { + "surface": "imessage.read", + "capability_package": "bluebubbles", + "readiness_state": "ready", + "health_source": "python3 tools/validate_bluebubbles_child.py", + "redacted_health": { + "validator_ok": true, + "read_only_imessage": true, + "memory_domain": "secondbrain-personal", + "orgbrain_forbidden": true, + "package_runtime_claims": false + }, + "remaining_gap": "Profile aggregate runtime readiness still false until final acceptance packet." + }, + { + "surface": "mail.read", + "capability_package": "proton-rclone", + "readiness_state": "degraded", + "health_source": "MCP registration plus local service inventory", + "redacted_health": { + "mcp_server_enabled": true, + "proton_bridge_systemd_running": true, + "docker_email_gate": "exited-127", + "raw_mail_observed": false + }, + "remaining_gap": "Email gate repair or replacement and package child registration remain required." + }, + { + "surface": "calendar.read", + "capability_package": "proton-rclone", + "readiness_state": "degraded", + "health_source": "MCP registration plus local service inventory", + "redacted_health": { + "mcp_server_enabled": true, + "calendar_gate_running": true, + "proton_bridge_systemd_running": true, + "raw_calendar_events_observed": false + }, + "remaining_gap": "Calendar read has service posture but no governed package child runtime proof." + }, + { + "surface": "contacts.read", + "capability_package": "proton-rclone", + "readiness_state": "degraded", + "health_source": "MCP registration plus local service inventory", + "redacted_health": { + "mcp_server_enabled": true, + "docker_contacts_gate": "exited-127", + "raw_contacts_observed": false + }, + "remaining_gap": "Contacts gate repair or replacement and package child registration remain required." + }, + { + "surface": "drive.read", + "capability_package": "proton-rclone", + "readiness_state": "degraded", + "health_source": "rclone explicit-config about probe", + "redacted_health": { + "rclone_remote_present": true, + "rclone_about_probe": "ok-redacted", + "rclone_rc_unit": "disabled", + "rclone_proxy_unit": "disabled", + "drive_file_names_observed": false, + "drive_file_contents_observed": false + }, + "remaining_gap": "Drive read needs governed wrapper and package child before runtime readiness." + } + ], + "supervisor_posture": { + "mac_mini_bluebubbles": "package-validator-ok-redacted", + "proton_bridge_service": "active-running", + "proton_bridge_proxy_service": "active-running", + "rclone_rc_service": "disabled-inactive", + "rclone_proxy_service": "disabled-inactive" + }, + "named_runtime_gaps": [ + { + "id": "proton-email-gate-exited", + "severity": "must-fix", + "state": "sdo-email-gate exited-127", + "impact": "mail.read remains degraded" + }, + { + "id": "proton-contacts-gate-exited", + "severity": "must-fix", + "state": "sdo-contacts-gate exited-127", + "impact": "contacts.read remains degraded" + }, + { + "id": "stale-protonmail-bridge-container", + "severity": "follow-up", + "state": "stale sdo-protonmail-bridge container exists in Created state", + "impact": "duplicate service topology must be resolved before final runtime readiness" + }, + { + "id": "proton-rclone-child-unregistered", + "severity": "must-fix", + "state": "package candidate exists but no registered child workspace", + "impact": "Proton/rclone package cannot claim runtime readiness" + }, + { + "id": "secondbrain-apply-blocked", + "severity": "must-fix", + "state": "proposal route exists; durable apply remains blocked", + "impact": "personal memory intake is not durable yet" + }, + { + "id": "desktop-adapter-exposure-blocked", + "severity": "follow-up", + "state": "adapter lane must pick up the contract before desktop display", + "impact": "desktop app cannot display final personal-agent runtime readiness yet" + } + ], + "optional_reboot_power_loss_proof": { + "status": "not-run", + "required_for_final_always_on_claim": true, + "notes": "Current proof verifies supervisor posture and package validators, not reboot recovery." + }, + "observed_commands": [ + "python3 tools/validate_bluebubbles_child.py", + "hermes -p steev mcp list", + "systemctl --user show proton-bridge.service proton-bridge-proxy.service rclone-rc.service rclone-proxy.service -p Id -p LoadState -p ActiveState -p SubState -p UnitFileState --no-pager", + "docker ps -a --format '' | rg -i 'bluebubbles|proton|calendar|contacts|email|mail|rclone|sdo'", + "rclone --config /home/svrnty/.config/rclone/rclone.conf about proton: --json" + ], + "proof_policy": { + "mode": "redacted-only", + "forbidden_fields": [ + "raw_messages", + "message_text", + "mail_bodies", + "mail_subjects", + "sender_address", + "recipient_address", + "contact_details", + "calendar_event_details", + "drive_file_names", + "drive_file_contents", + "attachment_content", + "endpoint_payloads", + "credentials", + "secret_values" + ] + }, + "remaining_gates": { + "proton_email_gate_repair": "blocked-follow-up", + "proton_contacts_gate_repair": "blocked-follow-up", + "proton_rclone_child_registration": "blocked-follow-up", + "secondbrain_durable_apply": "blocked-follow-up", + "desktop_adapter_exposure": "blocked-follow-up", + "reboot_power_loss_drill": "optional-follow-up", + "final_acceptance_packet": "blocked-follow-up" + } +} diff --git a/docs/supersession/2026-06-14-personal-agent-context-runtime-supersession-register.md b/docs/supersession/2026-06-14-personal-agent-context-runtime-supersession-register.md index 07fac33..26ed545 100644 --- a/docs/supersession/2026-06-14-personal-agent-context-runtime-supersession-register.md +++ b/docs/supersession/2026-06-14-personal-agent-context-runtime-supersession-register.md @@ -40,6 +40,7 @@ desktop exposure must be treated as one of: | Personal memory durable apply | blocked-follow-up | Owning Secondbrain/curator route must approve and apply; profile/capability packages do not write durable memory | | Personal-agent Conductor/Curator service handoff | active-authority | `docs/contracts/personal-agent-conductor-curator-service-handoff.json` gives route and hygiene lanes a redacted service map | | Conductor/curator adoption | blocked-follow-up | Owning lanes must explicitly pick up the handoff; this profile does not mutate them | +| Personal-agent runtime readiness snapshot | active-authority | `docs/contracts/personal-agent-runtime-readiness-snapshot.json` names per-surface states and runtime gaps without aggregate readiness claim | | Desktop app exposure | blocked-follow-up | `PACR-008`, after adapter lane release | | Browser/Webwright host control | blocked-follow-up | `PACR-009`, explicit approval only | @@ -78,6 +79,7 @@ desktop exposure must be treated as one of: - Graph context should expose the Proton/rclone package candidate as the active standardization pickup, not a runtime-ready child package. - Graph context should expose the personal-agent Secondbrain proposal route as active while keeping durable apply blocked to Secondbrain/curator. - Graph context should expose the personal-agent Conductor/Curator service handoff as active, while adoption remains blocked to owning lanes. +- Graph context should expose the personal-agent runtime snapshot as degraded until the named runtime gaps close. - Graph context should not treat legacy Cortex Proton/rclone repositories as active authority. - Graph context should not treat duplicate Proton skills as separate current product surfaces. - Graph context should mark browser/Webwright host control as separate HITL runtime authority. diff --git a/tools/validate_steev_child.py b/tools/validate_steev_child.py index 84f7ce2..3845579 100755 --- a/tools/validate_steev_child.py +++ b/tools/validate_steev_child.py @@ -22,6 +22,7 @@ REQUIRED = [ "docs/contracts/personal-agent-proton-rclone-package.json", "docs/contracts/personal-agent-secondbrain-proposal-route.json", "docs/contracts/personal-agent-conductor-curator-service-handoff.json", + "docs/contracts/personal-agent-runtime-readiness-snapshot.json", "docs/prd/2026-06-14-personal-agent-context-runtime-prd.md", "docs/issues/2026-06-14-personal-agent-context-runtime-work-orders.md", "docs/supersession/2026-06-14-personal-agent-context-runtime-supersession-register.md", @@ -112,6 +113,23 @@ REQUIRED_HANDOFF_SERVICES = { "personal-agent.secondbrain.proposal-route", } +REQUIRED_RUNTIME_SURFACES = { + "imessage.read", + "mail.read", + "calendar.read", + "contacts.read", + "drive.read", +} + +REQUIRED_RUNTIME_GAPS = { + "proton-email-gate-exited", + "proton-contacts-gate-exited", + "stale-protonmail-bridge-container", + "proton-rclone-child-unregistered", + "secondbrain-apply-blocked", + "desktop-adapter-exposure-blocked", +} + def read_text(rel: str) -> str: return (ROOT / rel).read_text(encoding="utf-8") @@ -148,6 +166,7 @@ def main() -> int: "PACR-004", "PACR-005", "PACR-006", + "PACR-007", "status: candidate", "owner: jp", ]: @@ -739,6 +758,121 @@ def main() -> int: if remaining_gates.get(gate) != "blocked-follow-up": errors.append(f"service_handoff_remaining_gate_missing:{gate}") + runtime = load_json("docs/contracts/personal-agent-runtime-readiness-snapshot.json", errors) + if runtime: + if runtime.get("schema_version") != "personal-agent-runtime-readiness-snapshot/v1": + errors.append("runtime_snapshot_schema_version_invalid") + if runtime.get("status") != "active-redacted-runtime-snapshot": + errors.append("runtime_snapshot_status_invalid") + if runtime.get("profile_identity") != "personal-agent": + errors.append("runtime_snapshot_profile_identity_not_personal_agent") + if runtime.get("display_name") != "Steev": + errors.append("runtime_snapshot_display_name_not_steev") + if runtime.get("aggregate_runtime_state") != "degraded": + errors.append("runtime_snapshot_aggregate_not_degraded") + for key in ["runtime_readiness_claimed", "seed_readiness_claimed", "core_promotion_claimed"]: + if runtime.get(key) is not False: + errors.append(f"runtime_snapshot_overclaim:{key}") + if runtime.get("memory_target") != "secondbrain-personal": + errors.append("runtime_snapshot_memory_target_not_secondbrain_personal") + if "orgbrain" not in runtime.get("forbidden_memory_targets", []): + errors.append("runtime_snapshot_orgbrain_not_forbidden") + surfaces = runtime.get("surface_states", []) + surface_names = {surface.get("surface") for surface in surfaces} + missing_surfaces = sorted(REQUIRED_RUNTIME_SURFACES - surface_names) + if missing_surfaces: + errors.append(f"runtime_snapshot_surfaces_missing:{','.join(missing_surfaces)}") + state_by_surface = {surface.get("surface"): surface.get("readiness_state") for surface in surfaces} + if state_by_surface.get("imessage.read") != "ready": + errors.append("runtime_snapshot_imessage_not_ready") + for surface in ["mail.read", "calendar.read", "contacts.read", "drive.read"]: + if state_by_surface.get(surface) != "degraded": + errors.append(f"runtime_snapshot_surface_not_degraded:{surface}") + for surface in surfaces: + name = surface.get("surface", "") + if surface.get("readiness_state") not in {"ready", "degraded", "pending", "blocked", "disabled"}: + errors.append(f"runtime_snapshot_readiness_invalid:{name}") + if not surface.get("capability_package"): + errors.append(f"runtime_snapshot_package_missing:{name}") + if not surface.get("health_source"): + errors.append(f"runtime_snapshot_health_source_missing:{name}") + health = surface.get("redacted_health") + if not isinstance(health, dict): + errors.append(f"runtime_snapshot_health_not_object:{name}") + if "raw_mail_observed" in health and health.get("raw_mail_observed") is not False: + errors.append("runtime_snapshot_raw_mail_observed") + if "raw_calendar_events_observed" in health and health.get("raw_calendar_events_observed") is not False: + errors.append("runtime_snapshot_raw_calendar_observed") + if "raw_contacts_observed" in health and health.get("raw_contacts_observed") is not False: + errors.append("runtime_snapshot_raw_contacts_observed") + if "drive_file_names_observed" in health and health.get("drive_file_names_observed") is not False: + errors.append("runtime_snapshot_drive_file_names_observed") + if "drive_file_contents_observed" in health and health.get("drive_file_contents_observed") is not False: + errors.append("runtime_snapshot_drive_file_contents_observed") + imessage_health = next((surface.get("redacted_health", {}) for surface in surfaces if surface.get("surface") == "imessage.read"), {}) + if imessage_health.get("validator_ok") is not True: + errors.append("runtime_snapshot_bluebubbles_validator_not_ok") + if imessage_health.get("read_only_imessage") is not True: + errors.append("runtime_snapshot_imessage_not_readonly") + if imessage_health.get("package_runtime_claims") is not False: + errors.append("runtime_snapshot_bluebubbles_runtime_claim_overclaimed") + posture = runtime.get("supervisor_posture", {}) + expected_posture = { + "mac_mini_bluebubbles": "package-validator-ok-redacted", + "proton_bridge_service": "active-running", + "proton_bridge_proxy_service": "active-running", + "rclone_rc_service": "disabled-inactive", + "rclone_proxy_service": "disabled-inactive", + } + for key, expected in expected_posture.items(): + if posture.get(key) != expected: + errors.append(f"runtime_snapshot_posture_mismatch:{key}") + gaps = {gap.get("id") for gap in runtime.get("named_runtime_gaps", [])} + missing_gaps = sorted(REQUIRED_RUNTIME_GAPS - gaps) + if missing_gaps: + errors.append(f"runtime_snapshot_gaps_missing:{','.join(missing_gaps)}") + reboot = runtime.get("optional_reboot_power_loss_proof", {}) + if reboot.get("status") != "not-run": + errors.append("runtime_snapshot_reboot_status_not_not_run") + if reboot.get("required_for_final_always_on_claim") is not True: + errors.append("runtime_snapshot_reboot_not_required_for_final") + commands = set(runtime.get("observed_commands", [])) + for command in [ + "python3 tools/validate_bluebubbles_child.py", + "hermes -p steev mcp list", + "rclone --config /home/svrnty/.config/rclone/rclone.conf about proton: --json", + ]: + if command not in commands: + errors.append(f"runtime_snapshot_observed_command_missing:{command}") + forbidden_fields = set(runtime.get("proof_policy", {}).get("forbidden_fields", [])) + for field in [ + "raw_messages", + "message_text", + "mail_bodies", + "contact_details", + "calendar_event_details", + "drive_file_names", + "drive_file_contents", + "endpoint_payloads", + "credentials", + "secret_values", + ]: + if field not in forbidden_fields: + errors.append(f"runtime_snapshot_forbidden_field_missing:{field}") + remaining_gates = runtime.get("remaining_gates", {}) + for gate in [ + "proton_email_gate_repair", + "proton_contacts_gate_repair", + "proton_rclone_child_registration", + "secondbrain_durable_apply", + "desktop_adapter_exposure", + "final_acceptance_packet", + ]: + if remaining_gates.get(gate) != "blocked-follow-up": + errors.append(f"runtime_snapshot_remaining_gate_missing:{gate}") + if remaining_gates.get("reboot_power_loss_drill") != "optional-follow-up": + errors.append("runtime_snapshot_reboot_gate_missing") + for rel in ["AGENT.md", "CONTRACT.md", "DISCLOSURE.md", "README.md", "docs/STEEV-MASTER.md"]: path = ROOT / rel if not path.exists(): @@ -760,6 +894,7 @@ def main() -> int: "Proton/rclone package candidate", "Personal-agent Secondbrain proposal route", "Personal-agent Conductor/Curator service handoff", + "Personal-agent runtime readiness snapshot", "superseded", "legacy-reference", "blocked-follow-up", @@ -775,7 +910,7 @@ def main() -> int: result = { "ok": not errors, - "validator": "personal-agent-profile-distribution-v5", + "validator": "personal-agent-profile-distribution-v6", "checked": REQUIRED, "errors": errors, "warnings": [],