{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://ghrisx.com/schemas/verified-artifact-intake-v1.json",
  "title": "Ghrisx Verified Artifact Intake v1",
  "description": "Filesystem-backed private intake and separately human-approved public projection contract. A local draft, submission, reference, or demonstration is never verified merely because it exists.",
  "x-ghrisx-contract-id": "ghrisx.verified-artifact-intake.v1",
  "x-ghrisx-lifecycle": [
    "local_draft",
    "submitted_private",
    "triage",
    "needs_changes",
    "resubmitted",
    "accepted_for_projection",
    "publication_approved",
    "published_reviewed",
    "disputed",
    "correction_pending",
    "superseded",
    "withdrawn",
    "expired",
    "rejected",
    "deleted_private_record"
  ],
  "x-ghrisx-boundaries": {
    "local_draft": "Client-only. The server neither stores nor counts it.",
    "submission_consent": "Required separately from publication consent.",
    "publication_consent": "The separate intake boolean authorizes projection review but does not approve reviewer edits. After acceptance, the contributor must inspect and approve the exact server-derived projection digest; consent remains revocable through owner withdrawal.",
    "human_review": "Acceptance and publication approval require distinct environment-authenticated human reviewers. Machine principals cannot review or approve.",
    "privacy_minimization": "accept_for_projection may carry only the allowlisted public projection fields; private identifiers, owner credentials, reviewer identity and notes, IP, contact, and consent evidence are never eligible projection fields.",
    "contributor_authority": "A bounded contributor_authority_statement is required for private intake and correction. It asserts authority or rights to submit without requiring a legal name or contact, and it is never projected publicly.",
    "decision_reason": "Every authenticated human transition requires a nonempty bounded note. Review reasons remain private; public lifecycle history uses privacy-safe standardized reasons.",
    "conflict_disclosure": "accept_for_projection, approve_publication, and publish each require conflict_disclosed. False requires an omitted or empty conflict_note; true requires a nonempty bounded conflict_note. These declarations remain private review evidence.",
    "publication": "Publication is a separate explicit transition. Nothing auto-publishes.",
    "artifact_dates": "artifact_created_at is required at submission and may be privacy-safely corrected by the accepting reviewer, but cannot be later than the server-derived submitted_at. last_reviewed_at is server-derived at guarded publication and reviewed lifecycle changes.",
    "evidence_state": "A submitter proposes an evidence_state, but a real artifact cannot be accepted, published, or counted unless the accepting human explicitly sets the projection to evidence_reviewed or verified. Reference projections remain reference_only.",
    "counting": "Only a current, nonexpired, digest-valid published_reviewed projection whose guarded public countability decision is eligible, classified as artifact, carrying evidence, current consent, and the complete two-human threshold can count. Reference and demo projections never count. Totals are recomputed from current projections and drop on dispute, withdrawal, expiration, or supersession.",
    "duplicate_prevention": "Guarded publication computes an ephemeral SHA-256 fingerprint over substantive public fields only and rejects an exact active duplicate. IDs, timestamps, lifecycle/countability metadata, reviewer receipts, and digest are excluded. Governed supersession remains non-double-counting.",
    "dispute_reason": "An owner dispute requires a bounded nonempty reason for reviewable history. Owner withdrawal remains reason-optional because revoking publication consent never requires justification.",
    "withdrawal_authority": "Owner withdrawal revokes publication consent. Reviewer withdraw is a contestable administrative concealment that preserves contributor consent, requires a privacy-safe owner_reason, exposes withdrawal_kind on the public tombstone, and remains appealable through a same-private-record administrative_appeal_public_id marker rather than correction lineage.",
    "correction_appeal_uniqueness": "A rejected correction successor may reattach on appeal only when its parent has no replacement successor. A competing newer successor closes the abandoned appeal branch.",
    "lineage": "Public detail and summary expose both supersedes_public_id and superseded_by_public_id plus at most 32 privacy-safe lifecycle history entries. Reviewer identities and private notes never enter public history.",
    "qualified_review": "Non-ordinary medical, structural, electrical, agricultural, water, emergency, or other life-critical artifacts default off and cannot be accepted or published unless their exact class is listed in GHRISX_ARTIFACT_ENABLED_HAZARD_CLASSES, the accepting human has the matching configured qualification, and the public projection carries a nonempty qualified_review_receipt.",
    "storage_separation": "Private snapshots, public projections, minimized audit receipts, and content-free tombstones occupy separate protected stores. Runtime bodies, secrets, locks, and counters are excluded from packages.",
    "storage_atomicity": "Snapshots and minimized receipts are written to same-directory hidden exclusive files, flushed and fsynced when available, and atomically renamed into visibility. Stale hidden partials are ignored and cleaned after one hour.",
    "reviewer_rotation": "Reviewer permissions are environment-configured using narrow triage, project, approve, publish, moderate, and expire capabilities. Operational rotation changes custody without creating public rank.",
    "privacy": "Public projections omit private IDs, owner-token hashes, reviewer identities and notes, IP addresses, contact information, and consent evidence details.",
    "integrity": "The public digest is computed only over the canonical public projection with integrity.digest set to null.",
    "integrity_keyring": "Activated intake uses an external additive keyring outside site and storage roots. A signer snapshots one key ID/key pair. Eight retained keys is a stop boundary for new intake and publication; referenced keys cannot be retired or resealed by v1.",
    "bounded_access_audit": "Reviewer reads emit signed, five-minute-deduplicated, 30-day receipts in a 16-shard by 64-entry ring. These operational receipts never enter immutable decision transactions or public output.",
    "release_snapshot": "The offline v1 builder freezes only digest-valid public projections and the non-countable reference at an explicit UTC cutoff, emits identical EN/ES membership, zero capacity metrics, and an immutable manifest digest."
  },
  "x-ghrisx-endpoints": {
    "csrf": "GET /api/v1/artifact-intake/csrf",
    "submit": "POST /api/v1/artifact-intake/submissions",
    "private_status": "GET /api/v1/artifact-intake/submissions/{private_id}",
    "owner_action": "POST /api/v1/artifact-intake/submissions/{private_id}/{correct|resubmit|approve-projection|dispute|appeal|withdraw|delete-private}",
    "review_queue": "GET /api/v1/artifact-intake/review?limit={1..100}&cursor={opaque}",
    "review_record": "GET /api/v1/artifact-intake/review/{private_id}",
    "review_transition": "POST /api/v1/artifact-intake/review/{private_id}/transition",
    "reconcile_expirations": "POST /api/v1/artifact-intake/maintenance/reconcile-expirations",
    "apply_retention": "POST /api/v1/artifact-intake/maintenance/apply-retention",
    "public_index": "GET /api/v1/artifacts",
    "public_projection": "GET /api/v1/artifacts/{public_id}",
    "baseline_release_snapshot": "GET /downloads/verified-artifact-snapshots/snap_20260825_verified_zero_v1.json"
  },
  "x-ghrisx-owner-projection-approval": {
    "eligible_state": "accepted_for_projection",
    "inspect_field": "record.public_projection_candidate_sha256",
    "inspect_field_source": "Server-derived lowercase SHA-256 of the exact canonical reviewed public projection candidate.",
    "action": "approve-projection",
    "request_body": {
      "projection_digest": "Exact 64-character lowercase hexadecimal digest returned by owner inspection."
    },
    "success_response": [
      "result.projection_digest",
      "result.projection_consent_recorded"
    ],
    "effect": "Records contributor consent only for the exact candidate bytes while remaining in accepted_for_projection. It does not publish or replace distinct-human publication approval.",
    "fail_closed": "A missing, malformed, stale, or nonmatching digest is rejected. Any changed projection requires fresh owner inspection and approval before publication can advance."
  },
  "x-ghrisx-submission-idempotency": {
    "header": "Idempotency-Key",
    "format": "^[A-Za-z0-9_-]{32,128}$",
    "browser_key": "A fresh 48-character lowercase hexadecimal key from 24 cryptographically random browser bytes is held only in memory for one unchanged draft.",
    "retry": "A lost-response retry sends the same canonical request with the same key and returns the same private case instead of creating a duplicate.",
    "draft_change": "Any draft edit invalidates the in-memory key; the next deliberate submission generates a new key.",
    "server_receipt": "The protected server stores only HMAC/hashed key reference, request digest, private ID, transaction ID, and integrity receipt; it never stores the raw key as a public or packaged value."
  },
  "x-ghrisx-owner-correction-idempotency": {
    "action": "correct",
    "required_state": "published_reviewed_or_later_public_successor_creation",
    "header": "Idempotency-Key",
    "format": "^[A-Za-z0-9_-]{32,128}$",
    "browser_key": "A fresh 48-character lowercase hexadecimal key from 24 cryptographically random browser bytes is held only in memory for one private ID and unchanged correction payload.",
    "retry": "A lost-response retry of the unchanged published-correction request sends the same key so the successor owner capability can be recovered without creating another successor.",
    "payload_change": "Changing the private ID or correction payload replaces the in-memory key; a successful response clears it.",
    "needs_changes": "The header remains optional when correct updates a needs_changes or existing correction_pending record without creating a new successor capability.",
    "server_receipt": "The protected server stores only a keyed reference, request digest, successor private ID, transaction ID, and integrity receipt; it never stores the raw key as public or packaged data."
  },
  "x-ghrisx-private-retention": {
    "active_unpublished_inactivity_days": 90,
    "terminal_private_grace_days": 30,
    "terminal_private_states": ["rejected", "withdrawn", "expired", "superseded"],
    "published_support": "The supporting private body remains through the bounded public expires_at deadline and then enters the same 30-day appeal/exit grace period before deletion.",
    "deletion_result": "The private body is deleted through the governed erasure transaction; only the minimum content-free proof required for truthful lineage remains."
  },
  "x-ghrisx-review-queue-pagination": {
    "default_limit": 50,
    "maximum_limit": 100,
    "cursor_format": "^[A-Za-z0-9_-]{16,256}$",
    "response_field": "next_cursor",
    "browser_behavior": "Load more follows only the server-provided opaque cursor, requests at most 50 cases, keeps at most 250 visible summaries, and retains credentials/cursor only in memory until Clear or an auth-form change."
  },
  "x-ghrisx-review-transition": {
    "required_base_fields": [
      "action",
      "note"
    ],
    "conflict_required_actions": [
      "accept_for_projection",
      "approve_publication",
      "publish"
    ],
    "conflict_fields": [
      "conflict_disclosed",
      "conflict_note"
    ],
    "owner_reason_required_actions": [
      "request_changes",
      "request_correction",
      "reject",
      "withdraw"
    ],
    "reviewer_withdrawal": {
      "meaning": "Administrative concealment of an existing public record; not contributor consent revocation.",
      "private_reason": "A bounded privacy-safe owner_reason is required and visible to the authenticated contributor.",
      "public_receipt": "The non-countable tombstone exposes withdrawal_kind=administrative_concealment and an identity-free generic history reason.",
      "appeal": "The protected owner may appeal the administrative concealment."
    },
    "public_reason": "A nonempty bounded public_reason is required at accept_for_projection, approve_publication, and publish. It is emitted without reviewer identity; the private note and conflict declaration remain private.",
    "projection_action": "accept_for_projection",
    "projection_allowlist": [
      "locale",
      "title",
      "summary",
      "artifact_created_at",
      "content_type",
      "content",
      "evidence",
      "limitations",
      "expires_at",
      "details",
      "artifact_lineage_key",
      "duplicate_review_receipt"
    ],
    "private_record_countable": false,
    "public_count_source": "Eligible, current, digest-valid public projections only; no mutable aggregate and no submitter-supplied countability.",
    "public_projection_fields": {
      "lineage": [
        "supersedes_public_id",
        "superseded_by_public_id",
        "history"
      ],
      "countability": [
        "eligible",
        "reason",
        "decision_at"
      ],
      "history_max_items": 32,
      "derived_public_dates": [
        "submitted_at",
        "last_reviewed_at"
      ]
    },
    "reviewer_environment_contract": {
      "variable": "GHRISX_ARTIFACT_REVIEWERS",
      "entry_required": ["kind", "active", "token_sha256", "permissions"],
      "kind": "human",
      "permissions": ["triage", "project", "approve", "publish", "moderate", "expire"],
      "rotation": "Rotate credentials and assignments operationally; permissions express temporary custody, never public or permanent rank."
    }
  },
  "type": "object",
  "additionalProperties": false,
  "required": [
    "artifact_type",
    "artifact_classification",
    "locale",
    "title",
    "summary",
    "artifact_created_at",
    "content_type",
    "content",
    "evidence",
    "limitations",
    "expires_at",
    "submission_consent",
    "publication_consent",
    "details",
    "contributor_authority_statement"
  ],
  "properties": {
    "artifact_type": {
      "enum": [
        "ark_manifest",
        "skill_map_record",
        "build_lab_canvas",
        "local_ark_charter",
        "transition_field_guide",
        "resilience_ledger_receipt",
        "wheel_contribution_record"
      ]
    },
    "artifact_classification": {
      "enum": [
        "artifact",
        "reference",
        "demo"
      ]
    },
    "locale": {
      "enum": [
        "en-US",
        "es-US"
      ]
    },
    "title": {
      "type": "string",
      "minLength": 1,
      "maxLength": 160
    },
    "summary": {
      "type": "string",
      "minLength": 1,
      "maxLength": 2000
    },
    "artifact_created_at": {
      "type": "string",
      "format": "date-time",
      "description": "Required artifact creation date. The server normalizes it to UTC and rejects future values."
    },
    "content_type": {
      "enum": [
        "text/plain",
        "application/json"
      ]
    },
    "content": {
      "oneOf": [
        {
          "type": "string",
          "minLength": 1,
          "maxLength": 49152
        },
        {
          "type": "object"
        },
        {
          "type": "array"
        }
      ]
    },
    "evidence": {
      "type": "array",
      "maxItems": 12,
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512
      }
    },
    "limitations": {
      "type": "array",
      "maxItems": 12,
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 512
      }
    },
    "expires_at": {
      "type": "string",
      "format": "date-time",
      "description": "Required for every intake-submitted artifact, reference, or demo; the server requires a future UTC-normalized horizon no more than 366 days away."
    },
    "submission_consent": {
      "const": true
    },
    "publication_consent": {
      "type": "boolean"
    },
    "contributor_authority_statement": {
      "type": "string",
      "minLength": 1,
      "maxLength": 2000,
      "description": "Private-only authority and rights assertion; never part of a public projection."
    },
    "details": {
      "type": "object",
      "additionalProperties": false,
      "required": [
        "generalized_location",
        "originating_instrument",
        "action_circle_relationship",
        "capacity_state",
        "health_state",
        "evidence_state",
        "claim_lanes",
        "sources",
        "responsible_public_role",
        "testing_method",
        "observed_result",
        "failure_record",
        "unresolved_questions",
        "reproduction_instructions",
        "accessibility_notes",
        "privacy_review_receipt",
        "license",
        "correction_channel",
        "withdrawal_channel",
        "hazard_class",
        "qualified_review_receipt"
      ],
      "properties": {
        "generalized_location": {
          "oneOf": [
            {"type": "null"},
            {"type": "string", "minLength": 1, "maxLength": 160}
          ]
        },
        "originating_instrument": {
          "enum": ["action_circles", "ark", "skill_map", "build_labs", "local_arks", "transition_field_guides", "resilience_ledger", "wheel"]
        },
        "action_circle_relationship": {
          "oneOf": [
            {"type": "null"},
            {"type": "string", "minLength": 1, "maxLength": 512}
          ]
        },
        "capacity_state": {
          "enum": ["proposed", "built", "tested", "taught", "replicated", "restored"]
        },
        "health_state": {
          "enum": ["active", "at_risk", "failed", "disputed", "expired", "retired"]
        },
        "evidence_state": {
          "enum": ["unreviewed", "evidence_reviewed", "verified", "rejected", "disputed", "reference_only", "unknown"]
        },
        "claim_lanes": {
          "type": "array",
          "minItems": 1,
          "maxItems": 12,
          "uniqueItems": true,
          "items": {
            "enum": ["observed_record", "primary_source", "historical_analogy", "scientific_inference", "theology_interpretation", "amianism_cosmology", "speculative_scenario", "speculative_fiction", "fiction", "disputed_claim", "unknown", "modern_synthesis", "ancient_history", "amianism_doctrine", "hypothesis", "empirical_evidence", "qualified_technical_guidance"]
          }
        },
        "sources": {"$ref": "#/$defs/bounded_statements"},
        "responsible_public_role": {"type": "string", "minLength": 1, "maxLength": 160},
        "testing_method": {"type": "string", "minLength": 1, "maxLength": 2000},
        "observed_result": {"type": "string", "minLength": 1, "maxLength": 2000},
        "failure_record": {"type": "string", "minLength": 1, "maxLength": 2000},
        "unresolved_questions": {"$ref": "#/$defs/bounded_statements"},
        "reproduction_instructions": {"type": "string", "minLength": 1, "maxLength": 4000},
        "accessibility_notes": {"type": "string", "minLength": 1, "maxLength": 2000},
        "privacy_review_receipt": {
          "oneOf": [
            {"type": "null"},
            {"type": "string", "minLength": 1, "maxLength": 2000}
          ]
        },
        "license": {
          "enum": ["CC-BY-4.0", "CC0-1.0", "MIT", "Apache-2.0", "GPL-3.0-or-later", "All-Rights-Reserved"]
        },
        "correction_channel": {"type": "string", "minLength": 1, "maxLength": 512},
        "withdrawal_channel": {"type": "string", "minLength": 1, "maxLength": 512},
        "hazard_class": {
          "enum": ["ordinary", "medical", "structural", "electrical", "agricultural", "water", "emergency", "life_critical_other"]
        },
        "qualified_review_receipt": {
          "oneOf": [
            {"type": "null"},
            {"type": "string", "minLength": 1, "maxLength": 2000}
          ]
        }
      }
    }
  },
  "$defs": {
    "bounded_statements": {
      "type": "array",
      "maxItems": 12,
      "uniqueItems": true,
      "items": {"type": "string", "minLength": 1, "maxLength": 512}
    }
  },
  "allOf": [
    {
      "if": {
        "properties": {
          "content_type": {
            "const": "text/plain"
          }
        }
      },
      "then": {
        "properties": {
          "content": {
            "type": "string"
          }
        }
      }
    },
    {
      "if": {
        "properties": {
          "content_type": {
            "const": "application/json"
          }
        }
      },
      "then": {
        "properties": {
          "content": {
            "oneOf": [
              {
                "type": "object"
              },
              {
                "type": "array"
              }
            ]
          }
        }
      }
    }
  ]
}
