diff --git a/.github/workflows/workspace-recall-promotion.yml b/.github/workflows/workspace-recall-promotion.yml new file mode 100644 index 0000000..b955251 --- /dev/null +++ b/.github/workflows/workspace-recall-promotion.yml @@ -0,0 +1,33 @@ +name: workspace-recall-promotion + +on: + pull_request: + paths: + - "docs/workspace-recall-promotion.md" + - "schemas/workspace-recall-promotion-packet.schema.json" + - "examples/workspace-recall/**" + - "scripts/validate_workspace_recall_promotion_packet.py" + - ".github/workflows/workspace-recall-promotion.yml" + - "Makefile" + push: + branches: + - main + paths: + - "docs/workspace-recall-promotion.md" + - "schemas/workspace-recall-promotion-packet.schema.json" + - "examples/workspace-recall/**" + - "scripts/validate_workspace_recall_promotion_packet.py" + - ".github/workflows/workspace-recall-promotion.yml" + - "Makefile" + workflow_dispatch: + +jobs: + validate-workspace-recall-promotion: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.11" + - name: Validate Workspace Recall promotion packet + run: make validate-workspace-recall-promotion diff --git a/Makefile b/Makefile index 193991e..404d2e6 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ PYTHON ?= python -.PHONY: validate-upstreams validate-python validate-deploy-assets validate-agent-learning-proposal validate-governed-learning-lifecycle validate local-preflight local-up local-smoke local-debug local-down +.PHONY: validate-upstreams validate-python validate-deploy-assets validate-agent-learning-proposal validate-governed-learning-lifecycle validate-workspace-recall-promotion validate local-preflight local-up local-smoke local-debug local-down validate-upstreams: $(PYTHON) scripts/validate_upstreams.py third_party/upstreams.lock.yaml @@ -20,6 +20,9 @@ validate-agent-learning-proposal: validate-governed-learning-lifecycle: $(PYTHON) scripts/validate_governed_learning_lifecycle.py +validate-workspace-recall-promotion: + $(PYTHON) scripts/validate_workspace_recall_promotion_packet.py + validate: validate-upstreams validate-python validate-deploy-assets local-preflight: diff --git a/docs/workspace-recall-promotion.md b/docs/workspace-recall-promotion.md new file mode 100644 index 0000000..29c9727 --- /dev/null +++ b/docs/workspace-recall-promotion.md @@ -0,0 +1,44 @@ +# Workspace Recall Promotion + +## Purpose + +This document defines the Memory Mesh handoff for Workspace Context Fabric recall candidates. + +Prophet Workspace owns the workroom-facing `RecallCandidate` object. Memory Mesh owns the review and promotion path for durable recall records. + +## Boundary + +The v0.1 path is review-only by default: + +```text +Workspace RecallCandidate + -> WorkspaceRecallPromotionPacket + -> AgentLearningProposal-compatible review queue + -> approved durable record only after review +``` + +Memory Mesh does not silently promote workspace context into durable recall. The packet preserves refs to the workroom, context graph, runtime binding, AgentPlane evidence, platform evidence, and policy decisions. + +## Object + +The first object is: + +```text +schemas/workspace-recall-promotion-packet.schema.json +examples/workspace-recall/promotion-packet.example.json +``` + +## Required posture + +- source workspace refs are preserved; +- review mode defaults to `review_only`; +- raw sensitive payload storage is false in the example; +- durable action is disabled until review approval; +- evidence and policy refs are mandatory; +- AgentPlane and Prophet Platform refs remain external authority refs. + +## Validation + +```bash +python scripts/validate_workspace_recall_promotion_packet.py +``` diff --git a/examples/workspace-recall/promotion-packet.example.json b/examples/workspace-recall/promotion-packet.example.json new file mode 100644 index 0000000..d01df67 --- /dev/null +++ b/examples/workspace-recall/promotion-packet.example.json @@ -0,0 +1,58 @@ +{ + "apiVersion": "memory.mesh.workspace-recall-promotion/v1", + "kind": "WorkspaceRecallPromotionPacket", + "packetId": "workspace-recall-promotion-demo-0001", + "createdAt": "2026-05-22T17:00:00Z", + "sourceWorkspace": { + "workroomRef": "workroom://workroom-demo-0001", + "professionalWorkroomRef": "professional-workroom://workroom-demo-0001", + "contextGraphRef": "ctxgraph-demo-0001", + "runtimeBindingRef": "runtime-binding-demo-0001", + "agentPlaneEvidenceRef": "agentplane://evidence/workroom-context-demo-0001", + "platformRecordRef": "platform://workspace-context-record-demo-0001" + }, + "candidate": { + "recallCandidateRef": "recall-candidate-demo-0001", + "summary": "Workspace context should remain workroom-bound before promotion.", + "sourceNodeRefs": [ + "ctxnode-demo-0002" + ], + "scope": "workroom", + "confidence": 0.91, + "reviewState": "pending" + }, + "review": { + "mode": "review_only", + "required": true, + "status": "pending", + "reviewerRefs": [ + "human:workspace-owner" + ], + "approvalRef": null, + "notes": "Review-only packet. Durable writeback is disabled pending approval." + }, + "destination": { + "scope": "project", + "targetRef": "SocioProphet/prophet-workspace", + "path": "docs/context-fabric.md", + "memoryNamespace": "workspace-context-fabric" + }, + "evidenceRefs": [ + "evidence://context-fabric/recall/demo-0001", + "agentplane://evidence/workroom-context-demo-0001", + "platform://workspace-context-record-demo-0001" + ], + "policyDecisionRefs": [ + "policy-decision://policy-demo-ai-use/decision-0001" + ], + "promotion": { + "enabled": false, + "performed": false, + "proposalRef": null, + "writebackRef": null + }, + "redaction": { + "rawPayloadStored": false, + "summary": "Only refs and reviewed summary are included." + } +} diff --git a/schemas/workspace-recall-promotion-packet.schema.json b/schemas/workspace-recall-promotion-packet.schema.json new file mode 100644 index 0000000..1d2611f --- /dev/null +++ b/schemas/workspace-recall-promotion-packet.schema.json @@ -0,0 +1,97 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.socioprophet.org/memory-mesh/workspace-recall-promotion-packet.schema.json", + "title": "WorkspaceRecallPromotionPacket", + "type": "object", + "additionalProperties": false, + "required": [ + "apiVersion", + "kind", + "packetId", + "createdAt", + "sourceWorkspace", + "candidate", + "review", + "destination", + "evidenceRefs", + "policyDecisionRefs", + "promotion" + ], + "properties": { + "apiVersion": { "const": "memory.mesh.workspace-recall-promotion/v1" }, + "kind": { "const": "WorkspaceRecallPromotionPacket" }, + "packetId": { "type": "string", "minLength": 1 }, + "createdAt": { "type": "string", "format": "date-time" }, + "sourceWorkspace": { + "type": "object", + "additionalProperties": false, + "required": ["workroomRef", "contextGraphRef", "runtimeBindingRef"], + "properties": { + "workroomRef": { "type": "string", "minLength": 1 }, + "professionalWorkroomRef": { "type": ["string", "null"] }, + "contextGraphRef": { "type": "string", "minLength": 1 }, + "runtimeBindingRef": { "type": "string", "minLength": 1 }, + "agentPlaneEvidenceRef": { "type": ["string", "null"] }, + "platformRecordRef": { "type": ["string", "null"] } + } + }, + "candidate": { + "type": "object", + "additionalProperties": false, + "required": ["recallCandidateRef", "summary", "sourceNodeRefs", "scope", "confidence", "reviewState"], + "properties": { + "recallCandidateRef": { "type": "string", "minLength": 1 }, + "summary": { "type": "string", "minLength": 1 }, + "sourceNodeRefs": { "type": "array", "items": { "type": "string" } }, + "scope": { "enum": ["user", "workroom", "tenant", "project", "organization"] }, + "confidence": { "type": "number", "minimum": 0, "maximum": 1 }, + "reviewState": { "enum": ["pending", "approved", "rejected", "superseded"] } + } + }, + "review": { + "type": "object", + "additionalProperties": false, + "required": ["mode", "required", "status", "reviewerRefs", "approvalRef"], + "properties": { + "mode": { "enum": ["review_only", "approved_writeback"] }, + "required": { "type": "boolean" }, + "status": { "enum": ["pending", "approved", "rejected", "superseded"] }, + "reviewerRefs": { "type": "array", "items": { "type": "string" } }, + "approvalRef": { "type": ["string", "null"] }, + "notes": { "type": ["string", "null"] } + } + }, + "destination": { + "type": "object", + "additionalProperties": false, + "required": ["scope", "targetRef", "path", "memoryNamespace"], + "properties": { + "scope": { "enum": ["repo", "project", "user", "organization", "enterprise"] }, + "targetRef": { "type": "string", "minLength": 1 }, + "path": { "type": "string", "minLength": 1 }, + "memoryNamespace": { "type": ["string", "null"] } + } + }, + "evidenceRefs": { "type": "array", "minItems": 1, "items": { "type": "string" } }, + "policyDecisionRefs": { "type": "array", "minItems": 1, "items": { "type": "string" } }, + "promotion": { + "type": "object", + "additionalProperties": false, + "required": ["enabled", "performed", "proposalRef", "writebackRef"], + "properties": { + "enabled": { "type": "boolean" }, + "performed": { "type": "boolean" }, + "proposalRef": { "type": ["string", "null"] }, + "writebackRef": { "type": ["string", "null"] } + } + }, + "redaction": { + "type": "object", + "additionalProperties": false, + "properties": { + "rawPayloadStored": { "type": "boolean" }, + "summary": { "type": "string" } + } + } + } +} diff --git a/scripts/validate_workspace_recall_promotion_packet.py b/scripts/validate_workspace_recall_promotion_packet.py new file mode 100644 index 0000000..7d84b9b --- /dev/null +++ b/scripts/validate_workspace_recall_promotion_packet.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +"""Validate WorkspaceRecallPromotionPacket example.""" + +import json +import sys +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA = ROOT / "schemas/workspace-recall-promotion-packet.schema.json" +EXAMPLE = ROOT / "examples/workspace-recall/promotion-packet.example.json" + + +def main(): + try: + schema = json.loads(SCHEMA.read_text(encoding="utf-8")) + example = json.loads(EXAMPLE.read_text(encoding="utf-8")) + for key in schema["required"]: + if key not in example: + raise AssertionError(f"missing {key}") + assert example["apiVersion"] == "memory.mesh.workspace-recall-promotion/v1" + assert example["kind"] == "WorkspaceRecallPromotionPacket" + assert example["sourceWorkspace"]["workroomRef"].startswith("workroom://") + assert example["sourceWorkspace"]["contextGraphRef"] + assert example["candidate"]["recallCandidateRef"] + assert example["review"]["mode"] == "review_only" + assert example["review"]["required"] is True + assert example["promotion"]["enabled"] is False + assert example["promotion"]["performed"] is False + assert example["evidenceRefs"] + assert example["policyDecisionRefs"] + except Exception as exc: + print(f"ERR: {exc}", file=sys.stderr) + return 2 + print("OK: WorkspaceRecallPromotionPacket validation passed") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())