# BOUNDARY DECLARATION SCHEMA -- Plugin Manifest Template

**Purpose:** Schema for the Layer-1 manifest every plugin submits to the Isolation Verifier at install time. The verifier rejects any manifest missing any required field; rejection is returned to Phase 5 for repair.

**Pattern origin:** OSGi Core Module-Layer manifest + WASI capability-grant list.

---

## Schema (YAML)

```yaml
# boundary-declaration-manifest.yaml
manifest_version: "1.0"          # SemVer. MAJOR bump on any schema change.

plugin:
  id: "evaluator"                # Unique plugin identifier. Must match host registry.
  role: "evaluator"              # One of: ram | evaluator | peer.
  version: "0.1.0"               # SemVer of the plugin itself.
  manifest_version_count: 1      # Incremented on every re-install via Phase A rebuild.

owned_path_globs:                # REQUIRED. Every path the plugin may read or write.
  - "evaluator/references/**"
  - "evaluator/templates/**"
  - "evaluator/skills/**"
  - "state/evaluator/**"
  # NOTE: No path may begin with another plugin's owned root.
  # NOTE: No glob may traverse via ".." out of the plugin's assigned silo.

owned_state_key_prefixes:        # REQUIRED. Every state-manager key-prefix the plugin may touch.
  - "evaluator:frame-registry:"
  - "evaluator:search-ledger:"
  - "evaluator:isolation-verifier:"
  # NOTE: Prefixes MUST be distinct from every other plugin's declared prefixes.
  # NOTE: Each prefix includes its terminator character so "evaluator:" does not swallow "evaluator-sibling:".

allowed_retrieval_capabilities:  # REQUIRED. Every retrieval surface the plugin may call.
  - capability_id: "evaluator-corpus-v1"
    surface_type: "document-corpus"
    surface_uri: "file://evaluator/references/frame-methodology-packs/"
    token_issued_at: "install-time"
  - capability_id: "evaluator-web-search-v1"
    surface_type: "web-search"
    surface_uri: "https://api.example.org/search"
    token_issued_at: "install-time"
  # NOTE: No capability_id may be declared by any other plugin.
  # NOTE: Shared engine / cache / index / vector-store / embedding-store / model-API / DB-connection
  # IS A FAILURE. Each plugin must have its own surface instance, not a partitioned shared one.

library_root_hash:               # REQUIRED. Merkle root at install snapshot.
  algorithm: "sha256"
  root: "0x<64-hex-char-hash>"
  leaf_count: 0                  # Filled in by Layer-2 capture.
  baseline_captured_at: null     # Filled in by Layer-2 capture.

cross_cutting_artifacts:         # Optional; required if plugin owns any artifact consumed across components.
  - artifact_id: "frame-registry"
    owner: "evaluator.frame-divergence-gate"
    readable_by: ["evaluator.frame-host", "evaluator.audit-method-engine", "evaluator.self-audit-resistance-monitor"]
    writable_by: ["evaluator.frame-host", "evaluator.frame-divergence-gate"]
    path_root: "state/evaluator/frame-registry/"
    schema_version: "1.0"
    # NOTE: No RAM component may appear in readable_by or writable_by for any Evaluator artifact,
    # and no Evaluator component may appear for any RAM artifact.

primitive_availability:          # REQUIRED. Declared by the plugin host, not the plugin, but carried here.
  filesystem_event_api: "fsevents"  # One of: inotify | auditd | fsevents | hash-poll.
  namespace_primitive: "in-process-prefix"  # One of: kernel-namespaces | in-process-prefix.
  retrieval_sandbox: "wrapper"   # One of: wasi | jif | wrapper.
  tick_definition: "invocation-boundary"  # One of: invocation-boundary | periodic | hybrid.
  chaos_authorization: "side-environment"  # One of: side-environment | live-with-override.

lock_state:                      # Filled in after Layer-2 success.
  locked: false
  locked_at: null
  expansion_attempts: []
```

---

## Required Fields and Rejection Rules

| Field | Required | Rejection Condition |
|---|---|---|
| `manifest_version` | Yes | Missing or non-SemVer. |
| `plugin.id` | Yes | Missing or collides with another plugin's id. |
| `plugin.role` | Yes | Not in {ram, evaluator, peer}. |
| `owned_path_globs` | Yes | Missing, empty, or intersects another plugin's globs (HALT: doctrinal failure for RAM<->Evaluator intersection). |
| `owned_state_key_prefixes` | Yes | Missing, empty, or intersects another plugin's prefixes (HALT if RAM<->Evaluator). |
| `allowed_retrieval_capabilities` | Yes | Missing, empty, or shares a `capability_id` with another plugin (HALT if RAM<->Evaluator). |
| `library_root_hash` | Yes | Missing, not SHA-256, or equals another plugin's root (HALT if RAM<->Evaluator AND file-set intersection non-empty). |
| `primitive_availability` | Yes | Any sub-field missing. Declares the fallback tier per `PLUGIN_HOST_FALLBACKS.md`. |

---

## Cross-Plugin Intersection Check Pseudocode

```
for each pair (p1, p2) of plugins:
  if p1.owned_path_globs intersects p2.owned_path_globs:
    if (p1.role == "ram" and p2.role == "evaluator") or reverse:
      HALT: doctrinal failure, return to Phase 5
    else:
      FAIL: peer intersection; request manifest repair
  # repeat for owned_state_key_prefixes, allowed_retrieval_capabilities
  # Merkle root: check library_root_hash equality AND file-set intersection
```

---

## Immutability and Re-Issue

Once a manifest is Layer-1 accepted and Layer-2 captured, it is LOCKED (Layer 6). Runtime boundary expansion requires a new manifest with `manifest_version_count` incremented and a full Phase A + Phase B re-run. Any runtime attempt to alter a locked manifest is itself an integrity-breaking violation.

---

## Example Output -- Boundary Declaration Manifest Verification Record

```yaml
verification_record:
  record_id: "BDMR-<ulid>"
  generated_at: "<ISO-8601>"
  plugins_examined: ["ram", "evaluator", ...]
  per_axis_verdict:
    path_glob_intersection: "PASS"
    state_prefix_intersection: "PASS"
    capability_identifier_intersection: "PASS"
    library_root_distinctness: "PASS"
    cross_cutting_artifact_distinctness: "PASS"
  overall_verdict: "PASS"
  failures: []
  signed_by: "isolation-verifier@evaluator"
```

A single FAIL in any axis flips `overall_verdict` to `FAIL` and returns the build to Phase 5.
