Skip to content
Open
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
1 change: 1 addition & 0 deletions .claude/worktrees/zealous-feistel
Submodule zealous-feistel added at 276075
139 changes: 139 additions & 0 deletions packages/core/__tests__/constraint-language.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,145 @@ describe("validateConstraintEnvelope", () => {
expect(result.mode).toBe("legacy");
});

// -------------------------------------------------------------------------
// migrationAttestation — entity_continuity structural precondition
// Refs: aeoess/agent-governance-vocabulary#8
// -------------------------------------------------------------------------

it("migrationAttestation with continuityVerified:true and all fields is valid", () => {
const envelope: ConstraintEnvelope = {
version: "cl-1.0",
migrationAttestation: {
schema: "https://soulboundrobots.ai/schemas/sbr-002-v1.json",
attestationUri: "https://eas.example/0xabc",
agentWallet: "0xdead",
continuityVerified: true,
issuedAt: "2026-04-20T00:00:00Z",
},
};
const result = validateConstraintEnvelope(envelope);
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});

it("migrationAttestation with continuityVerified:false fails validation", () => {
const envelope: ConstraintEnvelope = {
version: "cl-1.0",
migrationAttestation: {
schema: "https://soulboundrobots.ai/schemas/sbr-002-v1.json",
attestationUri: "https://eas.example/0xabc",
agentWallet: "0xdead",
continuityVerified: false,
issuedAt: "2026-04-20T00:00:00Z",
},
};
const result = validateConstraintEnvelope(envelope);
expect(result.valid).toBe(false);
expect(result.errors).toContain(
"migrationAttestation.continuityVerified must be true for envelope to activate",
);
});

it("migrationAttestation with empty schema fails validation", () => {
const envelope: ConstraintEnvelope = {
version: "cl-1.0",
migrationAttestation: {
schema: "",
attestationUri: "https://eas.example/0xabc",
agentWallet: "0xdead",
continuityVerified: true,
issuedAt: "2026-04-20T00:00:00Z",
},
};
const result = validateConstraintEnvelope(envelope);
expect(result.valid).toBe(false);
expect(result.errors).toContain(
"migrationAttestation.schema must be a non-empty string",
);
});

it("migrationAttestation with empty attestationUri fails validation", () => {
const envelope: ConstraintEnvelope = {
version: "cl-1.0",
migrationAttestation: {
schema: "https://soulboundrobots.ai/schemas/sbr-002-v1.json",
attestationUri: "",
agentWallet: "0xdead",
continuityVerified: true,
issuedAt: "2026-04-20T00:00:00Z",
},
};
const result = validateConstraintEnvelope(envelope);
expect(result.valid).toBe(false);
expect(result.errors).toContain(
"migrationAttestation.attestationUri must be a non-empty string",
);
});

it("migrationAttestation with empty agentWallet fails validation", () => {
const envelope: ConstraintEnvelope = {
version: "cl-1.0",
migrationAttestation: {
schema: "https://soulboundrobots.ai/schemas/sbr-002-v1.json",
attestationUri: "https://eas.example/0xabc",
agentWallet: "",
continuityVerified: true,
issuedAt: "2026-04-20T00:00:00Z",
},
};
const result = validateConstraintEnvelope(envelope);
expect(result.valid).toBe(false);
expect(result.errors).toContain(
"migrationAttestation.agentWallet must be a non-empty string",
);
});

it("migrationAttestation with empty issuedAt fails validation", () => {
const envelope: ConstraintEnvelope = {
version: "cl-1.0",
migrationAttestation: {
schema: "https://soulboundrobots.ai/schemas/sbr-002-v1.json",
attestationUri: "https://eas.example/0xabc",
agentWallet: "0xdead",
continuityVerified: true,
issuedAt: "",
},
};
const result = validateConstraintEnvelope(envelope);
expect(result.valid).toBe(false);
expect(result.errors).toContain(
"migrationAttestation.issuedAt must be a non-empty ISO8601 string",
);
});

it("migrationAttestation validates on legacy envelope too (forward-compatible)", () => {
const envelope: ConstraintEnvelope = {
migrationAttestation: {
schema: "https://soulboundrobots.ai/schemas/sbr-002-v1.json",
attestationUri: "https://eas.example/0xabc",
agentWallet: "0xdead",
continuityVerified: false,
issuedAt: "2026-04-20T00:00:00Z",
},
};
const result = validateConstraintEnvelope(envelope);
expect(result.valid).toBe(false);
expect(result.mode).toBe("legacy");
expect(result.errors).toContain(
"migrationAttestation.continuityVerified must be true for envelope to activate",
);
});

it("envelope without migrationAttestation is unaffected (field is optional)", () => {
const envelope: ConstraintEnvelope = {
version: "cl-1.0",
physical: { maxVelocityMps: 0.5 },
};
const result = validateConstraintEnvelope(envelope);
expect(result.valid).toBe(true);
expect(result.errors).toHaveLength(0);
});

it("CL-1.0 with mode:corridor-preapproved is valid", () => {
const envelope: ConstraintEnvelope = {
version: "cl-1.0",
Expand Down
23 changes: 23 additions & 0 deletions packages/core/src/constraint-language.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,29 @@ export function validateConstraintEnvelope(envelope: ConstraintEnvelope): Constr
}
}

// migrationAttestation validation applies regardless of version — the field
// is forward-compatible and its presence always requires the full attestation
// shape with continuityVerified === true as the structural precondition for
// scope grant.
if (envelope.migrationAttestation !== undefined) {
const ma = envelope.migrationAttestation;
if (ma.continuityVerified !== true) {
errors.push("migrationAttestation.continuityVerified must be true for envelope to activate");
}
if (typeof ma.schema !== "string" || ma.schema.length === 0) {
errors.push("migrationAttestation.schema must be a non-empty string");
}
if (typeof ma.attestationUri !== "string" || ma.attestationUri.length === 0) {
errors.push("migrationAttestation.attestationUri must be a non-empty string");
}
if (typeof ma.agentWallet !== "string" || ma.agentWallet.length === 0) {
errors.push("migrationAttestation.agentWallet must be a non-empty string");
}
if (typeof ma.issuedAt !== "string" || ma.issuedAt.length === 0) {
errors.push("migrationAttestation.issuedAt must be a non-empty ISO8601 string");
}
}

return { valid: errors.length === 0, errors, mode };
}

Expand Down
22 changes: 22 additions & 0 deletions packages/core/src/types/protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,27 @@ export interface ConstraintEnvelopeAttestation {
readonly requireForTiers?: readonly ApprovalTier[];
}

/**
* CL-1.0 migration attestation — proves agent identity continuity across
* embodied-AI migrations (body swaps, wallet rotations, runtime handoffs).
*
* Shape aligns with the SBR-002 (Soulbound Robots) reference schema. When
* this field is present on an envelope, `continuityVerified` must be `true`
* for the envelope to validate. This makes entity_continuity a structural
* precondition for scope grant rather than an advisory signal.
*
* Refs:
* - aeoess/agent-governance-vocabulary#8 (entity_continuity signal type)
* - https://soulboundrobots.ai/schemas/sbr-002-v1.json (reference schema)
*/
export interface ConstraintEnvelopeMigrationAttestation {
readonly schema: string;
readonly attestationUri: string;
readonly agentWallet: string;
readonly continuityVerified: boolean;
readonly issuedAt: ISO8601;
}

/**
* CL-1.0 constraint enforcement mode.
*/
Expand All @@ -92,6 +113,7 @@ export interface ConstraintEnvelope extends Partial<SintPhysicalConstraints> {
readonly behavioral?: ConstraintEnvelopeBehavioral;
readonly model?: ConstraintEnvelopeModel;
readonly attestation?: ConstraintEnvelopeAttestation;
readonly migrationAttestation?: ConstraintEnvelopeMigrationAttestation;
readonly dynamic?: ConstraintEnvelopeDynamic;
readonly execution?: ConstraintEnvelopeExecution;
readonly extensions?: Readonly<Record<string, unknown>>;
Expand Down
18 changes: 18 additions & 0 deletions packages/degraded-connectivity/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "@pshkv/degraded-connectivity",
"version": "0.3.0",
"type": "module",
"description": "Degraded-connectivity mode: offline T0/T1 autonomy with local buffer replay",
"main": "src/index.ts",
"scripts": {
"test": "vitest run"
},
"dependencies": {
"@pshkv/core": "workspace:*",
"@pshkv/gate-policy-gateway": "workspace:*",
"@pshkv/world-model-provenance": "workspace:*"
},
"devDependencies": {
"vitest": "^3.2.4"
}
}
Loading
Loading