Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,6 @@ local-debug:

local-down:
bash deploy/local/scripts/down-local.sh

validate-prophet-mesh-scope-mirror:
node scripts/validate-prophet-mesh-scope-mirror.mjs
65 changes: 65 additions & 0 deletions contracts/prophet-mesh/prophet-mesh-memory-scope.v0.1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"schemaVersion": "memory-mesh.cross-repo-scope-mirror.v0.1",
"kind": "CrossRepoScopeMirror",
"contractVersion": "v0.1",
"mirrorId": "memory-mesh:prophet-mesh-memory-scope:v0.1",
"createdAt": "2026-06-10T00:00:00Z",
"sourceAuthority": {
"repo": "SocioProphet/prophet-mesh",
"path": "specs/runtime-release-bundle.yaml",
"contractVersion": "v0.1",
"claim": "memory_scope field in execution_trace must be explicit and non-empty"
},
"mirrorAuthority": {
"repo": "SocioProphet/memory-mesh",
"path": "contracts/prophet-mesh/prophet-mesh-memory-scope.v0.1.json",
"attestation": "memory-mesh independently mirrors the memory-scope policy boundary established by prophet-mesh"
},
"scopePolicy": {
"requiredField": "execution_trace.memory_scope",
"allowedScopePatterns": [
"relationship_context:approved",
"noetica-session-local",
"noetica-session-local:*",
"unscoped"
],
"prohibitedValues": [null, ""],
"enforcement": "reject_if_absent_or_empty",
"effectBoundary": {
"workspaceWriteEnabled": false,
"externalSendEnabled": false,
"effectEnabled": false
}
},
"privatePreviewInvariants": [
"execution_trace_must_include_memory_scope",
"memory_scope_must_be_explicit",
"memory_scope_must_not_be_empty_string",
"memory_scope_must_match_allowed_pattern_or_be_scoped_local"
],
"nonProductionBoundary": {
"claim": "This mirror contract covers dry-run and receipt-only modes only. Live execution scope policy requires a separate contract version.",
"coveredModes": ["dry_run_receipt_preview", "receipt_only"],
"excludedModes": ["live_execution"]
},
"crossRepoTraceability": {
"prophetMeshAdapterRef": {
"repo": "SocioProphet/agentplane",
"path": "contracts/prophet-mesh/prophet-mesh-agentplane-adapter.v0.1.json",
"contractVersion": "v0.1",
"mergeCommit": "faa767f42028ad0f2475c993700cdbef8490a38e",
"contentSha256": "38a3edb62813521a62f257f3f952271255d25dc3a05a14d6b96f04a6ff9b4268",
"mode": "dry_run_receipt_preview"
},
"runtimeReleaseBundleContract": {
"repo": "SocioProphet/prophet-mesh",
"path": "specs/runtime-release-bundle.yaml",
"invariant": "execution_trace_must_include_memory_scope"
}
},
"promotionNotes": [
"Memory-scope authority was self-attested in prophet-mesh only prior to this mirror.",
"This contract closes the symmetry gap: registry mirrors choir authority, model-router mirrors routing policy, agentplane projects execution receipts, memory-mesh now mirrors memory-scope policy.",
"No live execution scope is claimed. Non-production boundary applies."
]
}
81 changes: 81 additions & 0 deletions scripts/validate-prophet-mesh-scope-mirror.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env node
/**
* Validate the prophet-mesh memory-scope mirror contract.
* Lane G — confirms the mirror is structurally sound and cross-repo refs are present.
*/
import { readFile } from 'fs/promises'
import { fileURLToPath } from 'url'

const CONTRACT_PATH = 'contracts/prophet-mesh/prophet-mesh-memory-scope.v0.1.json'
const REQUIRED_FIELDS = [
'schemaVersion', 'kind', 'contractVersion', 'mirrorId',
'sourceAuthority', 'mirrorAuthority', 'scopePolicy',
'privatePreviewInvariants', 'nonProductionBoundary', 'crossRepoTraceability'
]
const REQUIRED_INVARIANTS = [
'execution_trace_must_include_memory_scope',
'memory_scope_must_be_explicit',
'memory_scope_must_not_be_empty_string'
]
const REQUIRED_MODES = ['dry_run_receipt_preview', 'receipt_only']

function assert(condition, message) {
if (!condition) throw new Error(message)
}

async function main() {
const raw = await readFile(CONTRACT_PATH, 'utf8')
const contract = JSON.parse(raw)

for (const field of REQUIRED_FIELDS) {
assert(field in contract, `missing required field: ${field}`)
}

assert(contract.kind === 'CrossRepoScopeMirror', 'kind must be CrossRepoScopeMirror')
assert(contract.contractVersion === 'v0.1', 'contractVersion must be v0.1')

const policy = contract.scopePolicy
assert(policy.requiredField === 'execution_trace.memory_scope', 'scopePolicy.requiredField must be execution_trace.memory_scope')
assert(policy.enforcement === 'reject_if_absent_or_empty', 'scopePolicy.enforcement must be reject_if_absent_or_empty')
assert(policy.effectBoundary.effectEnabled === false, 'effectBoundary.effectEnabled must be false')
assert(policy.effectBoundary.workspaceWriteEnabled === false, 'effectBoundary.workspaceWriteEnabled must be false')

for (const invariant of REQUIRED_INVARIANTS) {
assert(
contract.privatePreviewInvariants.includes(invariant),
`missing required invariant: ${invariant}`
)
}

const boundary = contract.nonProductionBoundary
for (const mode of REQUIRED_MODES) {
assert(boundary.coveredModes.includes(mode), `nonProductionBoundary.coveredModes must include ${mode}`)
}
assert(!boundary.coveredModes.includes('live_execution'), 'live_execution must not be in coveredModes')

const trace = contract.crossRepoTraceability
assert(typeof trace.prophetMeshAdapterRef === 'object', 'crossRepoTraceability.prophetMeshAdapterRef required')
const ref = trace.prophetMeshAdapterRef
assert(ref.repo === 'SocioProphet/agentplane', 'adapter ref repo must be SocioProphet/agentplane')
assert(typeof ref.contentSha256 === 'string' && ref.contentSha256.length === 64, 'contentSha256 must be 64-char hex')
assert(ref.mode === 'dry_run_receipt_preview', 'adapter ref mode must be dry_run_receipt_preview')

console.log(JSON.stringify({
ok: true,
contractPath: CONTRACT_PATH,
mirrorId: contract.mirrorId,
scopePolicy: contract.scopePolicy.enforcement,
invariantsVerified: REQUIRED_INVARIANTS.length,
adapterRefSha256: ref.contentSha256.slice(0, 16) + '...',
nonProductionBoundary: boundary.coveredModes
}, null, 2))
}

main().catch((error) => {
console.error(error instanceof Error ? error.message : String(error))
process.exit(1)
})

if (process.argv[1] === fileURLToPath(import.meta.url)) {
// already runs via top-level await equivalent above
}
Loading