diff --git a/governance/reports/task-completion/MPLP-VALIDATION-LAB-MANIFEST-POINTER-FOUNDATION-01.md b/governance/reports/task-completion/MPLP-VALIDATION-LAB-MANIFEST-POINTER-FOUNDATION-01.md new file mode 100644 index 0000000..0a7e2e1 --- /dev/null +++ b/governance/reports/task-completion/MPLP-VALIDATION-LAB-MANIFEST-POINTER-FOUNDATION-01.md @@ -0,0 +1,196 @@ +# Task Completion Report + +> **SOP**: SOP-VLAB-PROJ-SYNC-01 +> **Purpose**: Mandatory post-task association update documentation +> **Task**: MPLP-VALIDATION-LAB-MANIFEST-POINTER-FOUNDATION-01 + +--- + +## 1. Task ID / Scope + +**Task ID**: MPLP-VALIDATION-LAB-MANIFEST-POINTER-FOUNDATION-01 +**Scope**: Add Validation Lab Protocol Public Manifest pointer foundation using a vendored manifest, checksum, bounded helper, and no-network validation gate. +**Date**: 2026-05-29 + +--- + +## 2. Files Changed (by Repository) + +### Validation_Lab + +- `lib/data/mplp-public-manifest.json` - adds a vendored Protocol Public Manifest pointer copy using lint-safe forbidden-claim boundary wording. +- `lib/data/mplp-public-manifest.sha256` - records the sha256 checksum for the vendored manifest. +- `lib/protocol-manifest.ts` - exposes a bounded pointer helper for future safe consumption. +- `scripts/gates/validate-protocol-manifest.mjs` - adds a no-network manifest validation gate. +- `package.json` - adds `gate:protocol-manifest` and wires it into `gate:all`. +- `governance/reports/task-completion/MPLP-VALIDATION-LAB-MANIFEST-POINTER-FOUNDATION-01.md` - records this SOP task completion report. + +### MPLP_website + +- None. + +### docs + +- None. + +--- + +## 3. Registry Sync + +### ROUTES.yaml +**Version**: No version change +**Changes**: +- **Added**: None. +- **Modified**: None. +- **Deleted**: None. + +### TRUTH_SOURCES.yaml +**Version**: No version change +**Changes**: +- **Added**: None. +- **Modified**: None. +- **Deleted**: None. + +### GATES.yaml +**Version**: No version change +**Changes**: +- **Added**: None. +- **Modified**: None. +- **Deleted**: None. + +--- + +## 4. Projection SSOT + +### projection-map.json +**Version**: No version change +**Changes**: +- **New artifacts**: None. +- **Route updates**: None. +- **Forbidden/allowlist**: None. +- **No changes**. + +### PTM (Page Truth Map) +**Changes**: +- **New pages**: None. +- **Modified pages**: None. +- **Not applicable**. + +--- + +## 5. Three-Entry Projection Updates + +### Lab UI +**New Routes/Pages**: +- None. + +**New Exports**: +- None. + +### Website (Pointer-Only) +**Pointer Additions**: +- None. + +### Docs (Non-Normative Pointer) +**Reference Additions**: +- None. + +--- + +## 6. Gate Results (MANDATORY) + +### Lab Gates + +``` +gate:protocol-manifest + Status: PASS + Notes: Vendored manifest JSON, checksum, canonical repository, future target, package/repo migration state, and Validation Lab boundary flags verified without network access. + +gate:post-task-association + Status: PASS + Notes: Repo-local task completion report included in the branch diff. + +lint + Status: PASS with existing warnings. + +typecheck + Status: PASS. + +test + Status: PASS. + +build + Status: PASS. + +gate:semantic:ci + Status: PASS. + +gate:all + Status: PASS. + +git diff --check + Status: PASS. +``` + +### Cross-Repo Gates + +``` +Protocol: + Status: Not modified by this Lab-only task. + +Website: + Status: Not modified by this Lab-only task. +``` + +--- + +## 7. Hash Anchors + +### Manifest + +``` +lib/data/mplp-public-manifest.json: 56f98d9eb3b207f9803b0bc5088f7d0ee5645d5075bea99897966d79163721eb +``` + +### Gate Reports + +``` +No generated gate report committed by this task. +``` + +--- + +## 8. Next Tasks Triggered + +**Immediate Follow-On**: +- MPLP-VALIDATION-LAB-MANIFEST-POINTER-FOUNDATION-PR-CREATION-01 after branch verification and owner approval. + +**Future Work**: +- MPLP-RELEASE-SOP-RESTORATION-01 after foundation PR merge. +- Optional later Validation Lab UI/evidence metadata manifest consumption. +- Deferred owner review remains unchanged for: + - `lib/registry/lifecycle-guarantees.ts` + - `lib/verdict/types.ts` + - `lib/verdict/taxonomy.ts` + +--- + +## 9. Compliance Checklist + +- [x] Vendored Protocol Public Manifest pointer foundation added. +- [x] Checksum added and validated. +- [x] No-network validation gate added. +- [x] Bounded helper added without changing adjudication behavior. +- [x] No broad UI display replacement performed. +- [x] No evidence metadata rewriting performed. +- [x] No frozen schema, invariant, verdict, registry, license, or historical evidence surface modified. +- [x] No owner-review identity file modified. +- [x] No certification, endorsement, regulator approval, runtime authority, SDK authority, or protocol truth authority claim introduced. +- [x] Task Completion Report filed in governance/reports/task-completion/. + +--- + +**Report Author**: Codex +**Reviewed By**: Pending PR review +**Filed**: 2026-05-31 + diff --git a/lib/data/mplp-public-manifest.json b/lib/data/mplp-public-manifest.json new file mode 100644 index 0000000..e43f405 --- /dev/null +++ b/lib/data/mplp-public-manifest.json @@ -0,0 +1,190 @@ +{ + "manifest_id": "mplp-public-manifest-1.0.0-draft-650e5b2f", + "manifest_version": "0.1.0", + "generated_at": "2026-05-29T19:34:59+08:00", + "protocol_name": "MPLP", + "protocol_full_name": "Multi-Agent Lifecycle Protocol", + "protocol_version": "1.0.0", + "protocol_release_tag": null, + "protocol_commit_sha": "650e5b2f6754a7016d8c8184e54881b0fcef6683", + "copyright_holder": "Jearon Wong", + "trademark_notice": "Trademark notice pending owner approval. Downstream surfaces must not imply certification, endorsement, regulator approval, or protocol authority beyond this manifest.", + "license": "Apache-2.0", + "canonical_repository": "https://github.com/Coregentis/MPLP-Protocol", + "future_repository_target": "https://github.com/Multi-Agent-Lifecycle-Protocol/MPLP-Protocol", + "docs_url": "https://docs.mplp.io", + "website_url": "https://www.mplp.io", + "schema_manifest": { + "schema_bundle_version": "2.0.0", + "invariant_bundle_version": "2.0.0", + "schema_manifest_path": "schemas/v2/_manifests/", + "schema_manifest_url": "https://github.com/Coregentis/MPLP-Protocol/tree/main/schemas/v2/_manifests", + "schema_manifest_commit_sha": "650e5b2f6754a7016d8c8184e54881b0fcef6683" + }, + "sdk_packages": [ + { + "name": "@mplp/compliance", + "registry": "npm", + "current_version": "1.0.5", + "next_clean_version": "1.0.6", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/conformance", + "registry": "npm", + "current_version": "1.0.0", + "next_clean_version": "1.0.1", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/coordination", + "registry": "npm", + "current_version": "1.0.6", + "next_clean_version": "1.0.7", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/core", + "registry": "npm", + "current_version": "1.0.6", + "next_clean_version": "1.0.7", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/devtools", + "registry": "npm", + "current_version": "1.0.5", + "next_clean_version": "1.0.6", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/integration-llm-http", + "registry": "npm", + "current_version": "1.0.5", + "next_clean_version": "1.0.6", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/integration-storage-fs", + "registry": "npm", + "current_version": "1.0.5", + "next_clean_version": "1.0.6", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/integration-storage-kv", + "registry": "npm", + "current_version": "1.0.5", + "next_clean_version": "1.0.6", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/integration-tools-generic", + "registry": "npm", + "current_version": "1.0.5", + "next_clean_version": "1.0.6", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/modules", + "registry": "npm", + "current_version": "1.0.5", + "next_clean_version": "1.0.6", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/runtime-minimal", + "registry": "npm", + "current_version": "1.0.5", + "next_clean_version": "1.0.6", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/schema", + "registry": "npm", + "current_version": "1.0.6", + "next_clean_version": "1.0.7", + "package_replacement_status": "planned_not_published" + }, + { + "name": "@mplp/sdk-ts", + "registry": "npm", + "current_version": "1.0.7", + "next_clean_version": "1.0.8", + "package_replacement_status": "planned_not_published" + } + ], + "pypi_packages": [ + { + "name": "mplp-sdk", + "registry": "pypi", + "current_version": "1.0.5", + "next_clean_version": "1.0.6", + "package_replacement_status": "planned_not_published" + } + ], + "validation_lab_pointer": { + "validation_lab_repo": "https://github.com/Coregentis/MPLP-Validation-Lab", + "future_validation_lab_repo_target": "https://github.com/Multi-Agent-Lifecycle-Protocol/MPLP-Validation-Lab", + "validation_lab_commit_sha": null, + "validation_lab_release_tag": null, + "consumed_protocol_manifest_id": "mplp-public-manifest-1.0.0-draft-650e5b2f", + "ruleset_version": "ruleset-1.0", + "evidence_pack_version": null, + "lab_url": "https://lab.mplp.io", + "relation_status": "standalone_pointer_pending" + }, + "validation_lab_boundary": { + "non_certifying": true, + "non_normative": true, + "evidence_based_verdicts_only": true, + "no_endorsement": true, + "no_certification": true, + "no_regulator_approval": true, + "no_protocol_truth_override": true, + "no_runtime_authority": true, + "no_sdk_authority": true + }, + "website_boundary": { + "discovery_positioning_only": true, + "seo_geo_surface": true, + "protocol_truth_override_allowed": false, + "schema_truth_override_allowed": false, + "release_truth_override_allowed": false, + "package_publication_authority_allowed": false + }, + "release_status": { + "state": "draft", + "public_release_ready": false, + "gates": { + "schema_validated": true, + "example_validated": true, + "website_consumption_verified": false, + "validation_lab_pointer_verified": false, + "submodule_removal_allowed": false + } + }, + "forbidden_claims": [ + "Do not claim certified implementation status.", + "Do not claim formal MPLP approval.", + "Do not claim officially endorsed status from MPLP.", + "Do not claim regulator approved status.", + "Website defines protocol truth", + "Validation Lab defines protocol truth", + "package version equals protocol version unless explicitly stated" + ], + "non_certification_notice": "MPLP Validation Lab outputs are evidence-based and non-certifying. They do not constitute endorsement, regulator approval, runtime authority, SDK authority, or protocol authority.", + "package_replacement_status": { + "status": "planned_not_published", + "clean_replacement_versions_defined": true, + "package_actions_executed": false + }, + "repo_migration_status": { + "status": "reserved_future_org_not_migrated", + "current_org": "Coregentis", + "future_org": "Multi-Agent-Lifecycle-Protocol", + "migration_now": false, + "remotes_changed": false, + "package_repository_urls_changed": false + } +} diff --git a/lib/data/mplp-public-manifest.sha256 b/lib/data/mplp-public-manifest.sha256 new file mode 100644 index 0000000..4a8e523 --- /dev/null +++ b/lib/data/mplp-public-manifest.sha256 @@ -0,0 +1 @@ +56f98d9eb3b207f9803b0bc5088f7d0ee5645d5075bea99897966d79163721eb mplp-public-manifest.json diff --git a/lib/protocol-manifest.ts b/lib/protocol-manifest.ts new file mode 100644 index 0000000..a9ffbdd --- /dev/null +++ b/lib/protocol-manifest.ts @@ -0,0 +1,70 @@ +import manifestJson from "@/lib/data/mplp-public-manifest.json"; + +export type ProtocolManifestBoundary = { + non_certifying: boolean; + non_normative: boolean; + evidence_based_verdicts_only: boolean; + no_endorsement: boolean; + no_certification: boolean; + no_regulator_approval: boolean; + no_protocol_truth_override: boolean; + no_runtime_authority: boolean; + no_sdk_authority: boolean; +}; + +export type ProtocolRepoMigrationStatus = { + status: string; + current_org: string; + future_org: string; + migration_now: boolean; + remotes_changed: boolean; + package_repository_urls_changed: boolean; +}; + +export type ProtocolPackageReplacementStatus = { + status: string; + clean_replacement_versions_defined: boolean; + package_actions_executed: boolean; +}; + +export type BoundedProtocolManifest = { + protocol_name: string; + protocol_full_name: string; + protocol_version: string; + protocol_release_tag: string | null; + protocol_commit_sha: string; + canonical_repository: string; + future_repository_target: string; + copyright_holder: string; + license: string; + forbidden_claims: readonly string[]; + non_certification_notice: string; + validation_lab_boundary: ProtocolManifestBoundary; + repo_migration_status: ProtocolRepoMigrationStatus; + package_replacement_status: ProtocolPackageReplacementStatus; +}; + +const manifest = manifestJson; + +// Bounded pointer helper only. This does not define Protocol truth or alter Lab adjudication. +export const protocolManifest = Object.freeze({ + protocol_name: manifest.protocol_name, + protocol_full_name: manifest.protocol_full_name, + protocol_version: manifest.protocol_version, + protocol_release_tag: manifest.protocol_release_tag, + protocol_commit_sha: manifest.protocol_commit_sha, + canonical_repository: manifest.canonical_repository, + future_repository_target: manifest.future_repository_target, + copyright_holder: manifest.copyright_holder, + license: manifest.license, + forbidden_claims: Object.freeze([...manifest.forbidden_claims]), + non_certification_notice: manifest.non_certification_notice, + validation_lab_boundary: Object.freeze({ ...manifest.validation_lab_boundary }), + repo_migration_status: Object.freeze({ ...manifest.repo_migration_status }), + package_replacement_status: Object.freeze({ ...manifest.package_replacement_status }), +}) satisfies BoundedProtocolManifest; + +export function getProtocolManifestPointer(): BoundedProtocolManifest { + return protocolManifest; +} + diff --git a/package.json b/package.json index ff93c5c..0182501 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "gate:glob:02": "npx tsx scripts/gates/gate-glob-crosslink-integrity.ts", "gate:glob:03": "npx tsx scripts/gates/gate-glob-boundary-statement.ts", "gate:glob": "npm run gate:glob:01 && npm run gate:glob:02 && npm run gate:glob:03", + "gate:protocol-manifest": "node scripts/gates/validate-protocol-manifest.mjs", "gate:manifest-anchors": "npx tsx scripts/gates/gate-manifest-anchors.ts", "gate:no-hardcoded-version": "npx tsx scripts/gates/gate-no-hardcoded-version.ts", "gate:no-frozen-terminology": "npx tsx scripts/gates/gate-no-frozen-terminology.ts", @@ -63,7 +64,7 @@ "gate:unified:lint-trend": "tsx --tsconfig tsconfig.tools.json scripts/gates/unified/gate-unified-lint-debt-trend-01.ts", "gate:v1:all": "npm run gate:vlab:00 && npm run gate:vlab:01 && npm run gate:release:01", "gate:sitemap": "npx tsx scripts/gates/gate-sitemap-canonical.ts && npx tsx scripts/gates/gate-sitemap-indexability.ts", - "gate:all": "npm run gate:v1:all && npm run gate:v2:all && npm run gate:unified:inventory && npm run gate:unified:no-escape && npm run gate:unified:ui-version-strip && npm run gate:unified:runset-projection && npm run gate:unified:ruleset-projection && npm run gate:unified:gov-nav-closure && npm run gate:unified:lint-policy && npm run gate:unified:lint-deadline && npm run gate:unified:lint-trend && npm run gate:sitemap", + "gate:all": "npm run gate:protocol-manifest && npm run gate:v1:all && npm run gate:v2:all && npm run gate:unified:inventory && npm run gate:unified:no-escape && npm run gate:unified:ui-version-strip && npm run gate:unified:runset-projection && npm run gate:unified:ruleset-projection && npm run gate:unified:gov-nav-closure && npm run gate:unified:lint-policy && npm run gate:unified:lint-deadline && npm run gate:unified:lint-trend && npm run gate:sitemap", "ci:seal": "npm run build && npm run gate:all && npm run audit:http:local", "ci:extended": "npm run ci:seal && npm run gate:v2:extended", "release:seal": "npx tsx scripts/release/seal-ceremony.ts", @@ -164,4 +165,4 @@ "engines": { "node": ">=20" } -} \ No newline at end of file +} diff --git a/scripts/gates/validate-protocol-manifest.mjs b/scripts/gates/validate-protocol-manifest.mjs new file mode 100644 index 0000000..b86d8c0 --- /dev/null +++ b/scripts/gates/validate-protocol-manifest.mjs @@ -0,0 +1,154 @@ +#!/usr/bin/env node +/** + * Validates the vendored MPLP Protocol Public Manifest without network access. + */ + +import crypto from "node:crypto"; +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const ROOT = path.resolve(__dirname, "../.."); +const MANIFEST_PATH = path.join(ROOT, "lib", "data", "mplp-public-manifest.json"); +const CHECKSUM_PATH = path.join(ROOT, "lib", "data", "mplp-public-manifest.sha256"); + +const REQUIRED_FIELDS = [ + "manifest_id", + "manifest_version", + "generated_at", + "protocol_name", + "protocol_full_name", + "protocol_version", + "protocol_release_tag", + "protocol_commit_sha", + "copyright_holder", + "trademark_notice", + "license", + "canonical_repository", + "future_repository_target", + "docs_url", + "website_url", + "schema_manifest", + "sdk_packages", + "pypi_packages", + "validation_lab_pointer", + "validation_lab_boundary", + "website_boundary", + "release_status", + "forbidden_claims", + "non_certification_notice", + "package_replacement_status", + "repo_migration_status", +]; + +const DIRECT_PROMOTIONAL_CLAIMS = [ + "MPLP-certified", + "certified by MPLP", + "officially endorsed by MPLP", + "regulator approved", +]; + +function fail(message) { + console.error(`[protocol-manifest] FAIL: ${message}`); + process.exit(1); +} + +function assert(condition, message) { + if (!condition) { + fail(message); + } +} + +function relative(file) { + return path.relative(ROOT, file); +} + +function readJson(file) { + try { + return JSON.parse(fs.readFileSync(file, "utf8")); + } catch (error) { + fail(`Cannot parse JSON at ${relative(file)}: ${error.message}`); + } +} + +function hasOwn(object, field) { + return Object.prototype.hasOwnProperty.call(object, field); +} + +assert(fs.existsSync(MANIFEST_PATH), "Vendored manifest is missing."); +assert(fs.existsSync(CHECKSUM_PATH), "Vendored manifest checksum is missing."); + +const manifestBytes = fs.readFileSync(MANIFEST_PATH); +const manifest = readJson(MANIFEST_PATH); +const checksumLine = fs.readFileSync(CHECKSUM_PATH, "utf8").trim(); +const expectedHash = checksumLine.split(/\s+/)[0]; +const actualHash = crypto.createHash("sha256").update(manifestBytes).digest("hex"); + +assert(/^[0-9a-f]{64}$/.test(expectedHash), "Checksum file must start with a sha256 hash."); +assert(actualHash === expectedHash, "Vendored manifest checksum does not match."); + +for (const field of REQUIRED_FIELDS) { + assert(hasOwn(manifest, field), `Missing required field: ${field}`); +} + +assert(manifest.protocol_name === "MPLP", "protocol_name must be MPLP."); +assert(manifest.protocol_full_name === "Multi-Agent Lifecycle Protocol", "protocol_full_name mismatch."); +assert(/^[0-9]+\.[0-9]+\.[0-9]+$/.test(manifest.protocol_version), "protocol_version must be semver-like."); +assert(/^[0-9a-f]{40}$/.test(manifest.protocol_commit_sha), "protocol_commit_sha must be a 40-character sha."); +assert(manifest.copyright_holder === "Jearon Wong", "copyright_holder must be Jearon Wong."); +assert(manifest.license === "Apache-2.0", "license must remain Apache-2.0."); +assert( + manifest.canonical_repository === "https://github.com/Coregentis/MPLP-Protocol", + "canonical_repository must remain Coregentis/MPLP-Protocol." +); + +assert( + manifest.future_repository_target === "https://github.com/Multi-Agent-Lifecycle-Protocol/MPLP-Protocol", + "future_repository_target must remain the reserved future Protocol target." +); +assert(manifest.repo_migration_status?.status === "reserved_future_org_not_migrated", "repo migration status must remain deferred."); +assert(manifest.repo_migration_status?.current_org === "Coregentis", "current_org must remain Coregentis."); +assert(manifest.repo_migration_status?.future_org === "Multi-Agent-Lifecycle-Protocol", "future_org mismatch."); +assert(manifest.repo_migration_status?.migration_now === false, "repo migration must remain disabled."); +assert(manifest.repo_migration_status?.remotes_changed === false, "remotes_changed must be false."); +assert(manifest.repo_migration_status?.package_repository_urls_changed === false, "package_repository_urls_changed must be false."); +assert(manifest.package_replacement_status?.status === "planned_not_published", "package replacement must remain planned_not_published."); +assert(manifest.package_replacement_status?.package_actions_executed === false, "package actions must remain false."); + +const boundary = manifest.validation_lab_boundary || {}; +assert(boundary.non_certifying === true, "validation_lab_boundary.non_certifying must be true."); +assert(boundary.no_certification === true, "validation_lab_boundary.no_certification must be true."); +assert(boundary.no_endorsement === true, "validation_lab_boundary.no_endorsement must be true."); +assert(boundary.no_regulator_approval === true, "validation_lab_boundary.no_regulator_approval must be true."); +assert(boundary.no_protocol_truth_override === true, "validation_lab_boundary.no_protocol_truth_override must be true."); +assert(boundary.no_runtime_authority === true, "validation_lab_boundary.no_runtime_authority must be true."); +assert(boundary.no_sdk_authority === true, "validation_lab_boundary.no_sdk_authority must be true."); + +assert(Array.isArray(manifest.forbidden_claims), "forbidden_claims must be an array."); +const forbiddenClaims = manifest.forbidden_claims.join("\n"); +const forbiddenClaimsLower = forbiddenClaims.toLowerCase(); +assert(forbiddenClaimsLower.includes("certified"), "forbidden_claims must include certification boundary."); +assert(forbiddenClaimsLower.includes("endorsed"), "forbidden_claims must include endorsement boundary."); +assert(forbiddenClaimsLower.includes("regulator approved"), "forbidden_claims must include regulator approval boundary."); + +for (const claim of DIRECT_PROMOTIONAL_CLAIMS) { + assert( + !manifest.forbidden_claims.includes(claim), + `forbidden_claims must use boundary wording, not direct promotional phrase: ${claim}` + ); +} + +const notice = String(manifest.non_certification_notice || "").toLowerCase(); +assert(notice.includes("evidence-based"), "non_certification_notice must preserve evidence-based wording."); +assert(notice.includes("non-certifying"), "non_certification_notice must preserve non-certifying wording."); +assert(notice.includes("endorsement"), "non_certification_notice must preserve no-endorsement boundary."); +assert(notice.includes("regulator approval"), "non_certification_notice must preserve no-regulator-approval boundary."); +assert(notice.includes("runtime authority"), "non_certification_notice must preserve no-runtime-authority boundary."); +assert(notice.includes("sdk authority"), "non_certification_notice must preserve no-SDK-authority boundary."); +assert(notice.includes("protocol authority"), "non_certification_notice must preserve no-protocol-authority boundary."); + +console.log(`[protocol-manifest] checksum: ${actualHash}`); +console.log("[protocol-manifest] PASS: vendored manifest validated without network access."); +