#!/usr/bin/env julia
#=
ORCaRzGate.jl
===============
Orphaned Recursive Capsule and Replay substrate, Z-Gate edition.

Design contract
---------------
1. Every admitted artefact is bytes first. Names and text are metadata only.
2. A transform advertised as lossless is accepted only after exact decode equality.
3. Raw objects are immutable, content-addressed, and never replaced by derivatives.
4. Unknown or malformed input returns a typed failure and remains preserved.
5. No model output, symbolic label, file extension, or decoded prose grants authority.
6. Network operation is absent from the trusted core. Optional network extensions must
   call the same admission, verification, and capability interfaces.
7. Julia standard libraries implement the complete base runtime. No non-Julia package manager or
   foreign script is required.
8. V.A.S.K., KEYCHAIN, Rota, House, and Z-Gate names identify mathematical or protocol
   objects only. They do not confer operating-system privilege.

Recommended Julia project commands
----------------------------------
    julia --project=. -e 'using Pkg; Pkg.activate("."); Pkg.instantiate()'
    julia --project=. ORCaRzGate.jl selftest
    julia --project=. ORCaRzGate.jl init ./ORCaR_ROOT
    julia --project=. ORCaRzGate.jl admit ./ORCaR_ROOT input.bin
    julia --project=. ORCaRzGate.jl verify ./ORCaR_ROOT

Optional native Julia extensions, never required by this file:
    julia --project=. -e 'using Pkg; Pkg.add(["JSON3","HTTP","SQLite","CodecZstd","StructTypes"])'

The optional packages are integration surfaces only. The trusted lossless object core,
codec arena, ledger, capsule creation, replay log, deterministic scheduler, permission
operators, and V.A.S.K. numerical laboratory run with Julia standard libraries.
=#

module ORCaRzGate

using SHA
using Dates
using UUIDs
using Random
using Printf
using TOML
using Tar
using LinearAlgebra
using SparseArrays
using Serialization
using Base64
using Logging

const VERSION = v"1.0.0"
const FORMAT_VERSION = 1
const OBJECT_PREFIX = "sha256"
const MAX_OBJECT_BYTES_DEFAULT = 1 << 30
const MAX_DECODED_BYTES_DEFAULT = 1 << 30
const MAX_TOKEN_BYTES_DEFAULT = 1 << 28
const RNA5_PREFIX = codeunits("RNA5:v1:") |> collect
const RNA5_STRANDS = UInt8['A','U','C','G','Z']
const BASKET_MAGIC = UInt8[0x4f,0x52,0x42,0x4b,0x01] # ORBK + version
const RLE_MAGIC = UInt8[0x4f,0x52,0x52,0x4c,0x01]    # ORRL + version
const TRANSPOSE_MAGIC = UInt8[0x4f,0x52,0x54,0x50,0x01] # ORTP + version
const CAPSULE_MANIFEST = "ORCAR_CAPSULE.toml"
const CORE_DIRS = (
    "objects", "metadata", "derived", "ledgers", "capsules", "workspaces",
    "quarantine", "exports", "checkpoints", "extensions", "research", "tmp"
)

# -----------------------------------------------------------------------------
# SECTION 00: Typed outcomes and invariants
# -----------------------------------------------------------------------------

@enum OutcomeCode::UInt16 begin
    OUTCOME_OK = 0
    OUTCOME_INVALID_ARGUMENT = 1
    OUTCOME_NOT_FOUND = 2
    OUTCOME_IO_ERROR = 3
    OUTCOME_LIMIT_EXCEEDED = 4
    OUTCOME_HASH_MISMATCH = 5
    OUTCOME_FORMAT_ERROR = 6
    OUTCOME_ROUNDTRIP_FAILURE = 7
    OUTCOME_POLICY_DENIED = 8
    OUTCOME_CONFLICT = 9
    OUTCOME_CANCELLED = 10
    OUTCOME_INTERNAL_ERROR = 11
end

struct Outcome{T}
    code::OutcomeCode
    value::Union{Nothing,T}
    message::String
    details::Dict{String,String}
end

ok(value::T; message::AbstractString="ok", details=Dict{String,String}()) where {T} =
    Outcome{T}(OUTCOME_OK, value, String(message), Dict{String,String}(details))

function fail(::Type{T}, code::OutcomeCode, message::AbstractString;
              details=Dict{String,String}()) where {T}
    code == OUTCOME_OK && throw(ArgumentError("failure cannot use OUTCOME_OK"))
    Outcome{T}(code, nothing, String(message), Dict{String,String}(details))
end

isok(o::Outcome) = o.code == OUTCOME_OK
unwrap(o::Outcome) = isok(o) ? something(o.value) : throw(ErrorException("$(o.code): $(o.message)"))

struct Limits
    max_object_bytes::Int64
    max_decoded_bytes::Int64
    max_token_bytes::Int64
    max_archive_entries::Int
    max_archive_bytes::Int64
end

Limits() = Limits(MAX_OBJECT_BYTES_DEFAULT, MAX_DECODED_BYTES_DEFAULT,
                  MAX_TOKEN_BYTES_DEFAULT, 100_000, 4 << 30)

struct ORCaRPaths
    root::String
    objects::String
    metadata::String
    derived::String
    ledgers::String
    capsules::String
    workspaces::String
    quarantine::String
    exports::String
    checkpoints::String
    extensions::String
    research::String
    tmp::String
    config::String
    organ_registry::String
    boot_ledger::String
    event_ledger::String
end

function paths(root::AbstractString)
    r = abspath(expanduser(String(root)))
    ORCaRPaths(r,
        joinpath(r,"objects"), joinpath(r,"metadata"), joinpath(r,"derived"),
        joinpath(r,"ledgers"), joinpath(r,"capsules"), joinpath(r,"workspaces"),
        joinpath(r,"quarantine"), joinpath(r,"exports"), joinpath(r,"checkpoints"),
        joinpath(r,"extensions"), joinpath(r,"research"), joinpath(r,"tmp"),
        joinpath(r,"ORCaR.toml"), joinpath(r,"organ_registry.toml"),
        joinpath(r,"ledgers","boot.toml"), joinpath(r,"ledgers","events.log"))
end

utcnow() = Dates.format(now(UTC), dateformat"yyyy-mm-ddTHH:MM:SS.sssZ")
hexsha(data::AbstractVector{UInt8}) = bytes2hex(sha256(data))

function file_sha256(path::AbstractString)
    open(path, "r") do io
        return bytes2hex(sha256(io))
    end
end

function checked_relpath(path::AbstractString)
    s = replace(String(path), '\\' => '/')
    isempty(s) && throw(ArgumentError("empty relative path"))
    startswith(s, "/") && throw(ArgumentError("absolute path prohibited"))
    occursin(r"^[A-Za-z]:", s) && throw(ArgumentError("drive path prohibited"))
    parts = split(s, '/'; keepempty=false)
    any(p -> p == ".." || p == ".", parts) && throw(ArgumentError("dot traversal prohibited"))
    any(isempty, parts) && throw(ArgumentError("empty component prohibited"))
    return join(parts, '/')
end

function atomic_write(path::AbstractString, data::AbstractVector{UInt8}; mode=nothing)
    parent = dirname(path)
    mkpath(parent)
    temporary = joinpath(parent, ".$(basename(path)).tmp-$(getpid())-$(uuid4())")
    committed = false
    try
        open(temporary, "w") do io
            write(io, data)
            flush(io)
            Base.Filesystem.fsync(io)
        end
        mode === nothing || chmod(temporary, mode)
        mv(temporary, path; force=true)
        committed = true
        return path
    finally
        !committed && ispath(temporary) && rm(temporary; force=true)
    end
end

atomic_write(path::AbstractString, text::AbstractString; mode=nothing) =
    atomic_write(path, Vector{UInt8}(codeunits(text)); mode=mode)

function read_bounded(path::AbstractString, maximum::Int64)
    stat = try
        lstat(path)
    catch e
        return fail(Vector{UInt8}, OUTCOME_NOT_FOUND, sprint(showerror,e))
    end
    isfile(stat) || return fail(Vector{UInt8}, OUTCOME_INVALID_ARGUMENT, "not a regular file")
    stat.size <= maximum || return fail(Vector{UInt8}, OUTCOME_LIMIT_EXCEEDED,
                                        "input exceeds configured byte limit";
                                        details=Dict("size"=>string(stat.size),"limit"=>string(maximum)))
    try
        return ok(read(path))
    catch e
        return fail(Vector{UInt8}, OUTCOME_IO_ERROR, sprint(showerror,e))
    end
end

# -----------------------------------------------------------------------------
# SECTION 01: Canonical text records and append-only hash chain
# -----------------------------------------------------------------------------

escape_field(s::AbstractString) = replace(replace(replace(replace(String(s),
    "%"=>"%25"), "\t"=>"%09"), "\n"=>"%0A"), "\r"=>"%0D")

function unescape_field(s::AbstractString)
    x = String(s)
    io = IOBuffer()
    i = firstindex(x)
    while i <= lastindex(x)
        if x[i] == '%'
            i + 2 <= lastindex(x) || throw(ArgumentError("truncated percent escape"))
            hx = x[nextind(x,i):nextind(x,nextind(x,i))]
            write(io, UInt8(parse(Int,hx;base=16)))
            i = nextind(x,nextind(x,nextind(x,i)))
        else
            write(io, codeunit(x,i))
            i = nextind(x,i)
        end
    end
    String(take!(io))
end

function canonical_pairs(d::AbstractDict)
    items = Pair{String,String}[]
    for (k,v) in d
        push!(items, string(k)=>string(v))
    end
    sort!(items; by=first)
    join((escape_field(k)*"="*escape_field(v) for (k,v) in items), "\t")
end

mutable struct HashLedger
    path::String
    lock::ReentrantLock
end
HashLedger(path::AbstractString) = HashLedger(String(path), ReentrantLock())

function last_ledger_hash(ledger::HashLedger)
    !isfile(ledger.path) && return repeat("0",64)
    lastline = ""
    open(ledger.path,"r") do io
        for line in eachline(io)
            isempty(line) || (lastline = line)
        end
    end
    isempty(lastline) && return repeat("0",64)
    fields = split(lastline, '\t')
    length(fields) >= 3 || throw(ErrorException("ledger has malformed final record"))
    fields[3]
end

function append_event!(ledger::HashLedger, kind::AbstractString,
                       fields::AbstractDict=Dict{String,String}())
    lock(ledger.lock) do
        mkpath(dirname(ledger.path))
        prev = last_ledger_hash(ledger)
        timestamp = utcnow()
        payload = canonical_pairs(merge(Dict("kind"=>String(kind)), Dict(string(k)=>string(v) for (k,v) in fields)))
        digest = hexsha(Vector{UInt8}(codeunits(join((timestamp,prev,payload),'\t'))))
        record = join((timestamp,prev,digest,payload),'\t') * "\n"
        open(ledger.path,"a") do io
            write(io,record)
            flush(io)
            Base.Filesystem.fsync(io)
        end
        return digest
    end
end

function verify_ledger(ledger::HashLedger)
    !isfile(ledger.path) && return ok((records=0,final_hash=repeat("0",64)))
    expected_prev = repeat("0",64)
    count = 0
    try
        open(ledger.path,"r") do io
            for line in eachline(io)
                isempty(line) && continue
                parts = split(line,'\t';limit=4)
                length(parts)==4 || throw(ArgumentError("record $(count+1) has wrong field count"))
                timestamp, prev, digest, payload = parts
                prev == expected_prev || throw(ArgumentError("record $(count+1) previous hash mismatch"))
                actual = hexsha(Vector{UInt8}(codeunits(join((timestamp,prev,payload),'\t'))))
                digest == actual || throw(ArgumentError("record $(count+1) digest mismatch"))
                expected_prev = digest
                count += 1
            end
        end
        return ok((records=count,final_hash=expected_prev))
    catch e
        return fail(NamedTuple, OUTCOME_HASH_MISMATCH, sprint(showerror,e))
    end
end

# -----------------------------------------------------------------------------
# SECTION 02: Initialisation, configuration, registry, and boot ledger
# -----------------------------------------------------------------------------

function default_config()
    Dict{String,Any}(
        "format_version"=>FORMAT_VERSION,
        "program_version"=>string(VERSION),
        "network_enabled"=>false,
        "immutable_raw_objects"=>true,
        "verify_every_transform"=>true,
        "max_object_bytes"=>MAX_OBJECT_BYTES_DEFAULT,
        "max_decoded_bytes"=>MAX_DECODED_BYTES_DEFAULT,
        "scheduler_workers"=>max(1,Threads.nthreads()-1),
        "vask_dimension"=>248,
        "extensions"=>Dict{String,Any}()
    )
end

function organ_registry()
    organs = [
        ("RawAdmission","immutable byte intake"),
        ("IdentityScanner","length, SHA-256, magic, entropy"),
        ("ObjectStore","content-addressed persistence"),
        ("HashLedger","append-only tamper evidence"),
        ("RNA5Codec","strict five-strand byte grammar"),
        ("BasketCodec","strict binary framed byte grammar"),
        ("RLECodec","bounded reversible run encoding"),
        ("TransposeCodec","bounded reversible matrix transposition"),
        ("CandidateArena","smallest verified candidate selection"),
        ("Capsule","deterministic manifest and tar transport"),
        ("Replay","ordered deterministic event replay"),
        ("Scheduler","bounded dependency execution"),
        ("CapabilityKernel","explicit permission checking"),
        ("CodeGraph","typed source relation storage"),
        ("VASKLab","isolated projector and activation computation"),
        ("RotaGraph","finite reversible labelled graph"),
        ("JuliaExtensionGate","optional package integration without core dependency")
    ]
    Dict("format_version"=>FORMAT_VERSION,"program_version"=>string(VERSION),
         "generated_utc"=>utcnow(),
         "organs"=>[Dict("name"=>n,"role"=>r,"status"=>"active") for (n,r) in organs])
end

function write_toml(path::AbstractString, d::AbstractDict)
    io = IOBuffer()
    TOML.print(io,d;sorted=true)
    atomic_write(path,take!(io))
end

function init_root(root::AbstractString)
    p = paths(root)
    mkpath(p.root)
    for name in CORE_DIRS
        mkpath(joinpath(p.root,name))
    end
    isfile(p.config) || write_toml(p.config,default_config())
    write_toml(p.organ_registry,organ_registry())
    boot = Dict("format_version"=>FORMAT_VERSION,"program_version"=>string(VERSION),
                "boot_id"=>string(uuid4()),"utc"=>utcnow(),"root"=>p.root,
                "julia_version"=>string(Base.VERSION),"word_size"=>Sys.WORD_SIZE,
                "kernel"=>string(Sys.KERNEL),"architecture"=>string(Sys.ARCH),
                "threads"=>Threads.nthreads())
    write_toml(p.boot_ledger,boot)
    ledger = HashLedger(p.event_ledger)
    append_event!(ledger,"root.initialised",Dict("root"=>p.root,"boot_id"=>boot["boot_id"]))
    return p
end

# -----------------------------------------------------------------------------
# SECTION 03: Byte identity, magic, entropy, and object metadata
# -----------------------------------------------------------------------------

function entropy_bits_per_byte(data::AbstractVector{UInt8})
    isempty(data) && return 0.0
    counts = zeros(Int,256)
    for b in data
        counts[Int(b)+1] += 1
    end
    n = length(data)
    h = 0.0
    for c in counts
        c == 0 && continue
        p = c/n
        h -= p*log2(p)
    end
    h
end

function detect_magic(data::AbstractVector{UInt8})
    starts(prefix) = length(data)>=length(prefix) && data[1:length(prefix)]==prefix
    starts(UInt8[0x37,0x7a,0xbc,0xaf,0x27,0x1c]) && return "application/x-7z-compressed"
    starts(UInt8[0x50,0x4b,0x03,0x04]) && return "application/zip"
    starts(UInt8[0x1f,0x8b]) && return "application/gzip"
    starts(UInt8[0x28,0xb5,0x2f,0xfd]) && return "application/zstd"
    starts(UInt8[0x25,0x50,0x44,0x46]) && return "application/pdf"
    starts(UInt8[0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a]) && return "image/png"
    starts(UInt8[0xff,0xd8,0xff]) && return "image/jpeg"
    starts(RNA5_PREFIX) && return "application/x-orcar-rna5"
    starts(BASKET_MAGIC) && return "application/x-orcar-basket"
    starts(RLE_MAGIC) && return "application/x-orcar-rle"
    starts(TRANSPOSE_MAGIC) && return "application/x-orcar-transpose"
    probe = data[1:min(end,8192)]
    isempty(probe) && return "application/x-empty"
    any(==(0x00),probe) && return "application/octet-stream"
    try
        String(copy(probe))
        return "text/plain; charset=utf-8"
    catch
        return "application/octet-stream"
    end
end

function scan_bytes(data::AbstractVector{UInt8}; declared_name::AbstractString="")
    Dict{String,Any}(
        "format_version"=>FORMAT_VERSION,
        "object_id"=>"$OBJECT_PREFIX:$(hexsha(data))",
        "sha256"=>hexsha(data),
        "byte_length"=>length(data),
        "magic"=>detect_magic(data),
        "entropy_bits_per_byte"=>entropy_bits_per_byte(data),
        "declared_name"=>String(declared_name),
        "admitted_utc"=>utcnow()
    )
end

function object_path(p::ORCaRPaths, digest::AbstractString)
    occursin(r"^[0-9a-f]{64}$",digest) || throw(ArgumentError("invalid SHA-256"))
    joinpath(p.objects,digest[1:2],digest[3:4],digest)
end
metadata_path(p::ORCaRPaths,digest::AbstractString)=joinpath(p.metadata,digest[1:2],"$digest.toml")

function store_bytes(p::ORCaRPaths, data::Vector{UInt8};
                     declared_name::AbstractString="", source::AbstractString="memory")
    meta = scan_bytes(data;declared_name=declared_name)
    digest = meta["sha256"]
    opath = object_path(p,digest)
    mpath = metadata_path(p,digest)
    if isfile(opath)
        file_sha256(opath)==digest || return fail(Dict{String,Any},OUTCOME_HASH_MISMATCH,
            "existing object path contains mismatched bytes")
    else
        atomic_write(opath,data;mode=0o444)
    end
    meta["source"] = String(source)
    meta["object_path"] = relpath(opath,p.root)
    meta["verified"] = true
    write_toml(mpath,meta)
    append_event!(HashLedger(p.event_ledger),"object.stored",
                  Dict("sha256"=>digest,"bytes"=>string(length(data)),"source"=>source))
    ok(meta)
end

function admit_file(p::ORCaRPaths, source_path::AbstractString; limits=Limits())
    result = read_bounded(source_path,limits.max_object_bytes)
    isok(result) || return fail(Dict{String,Any},result.code,result.message;details=result.details)
    store_bytes(p,unwrap(result);declared_name=basename(source_path),source=abspath(source_path))
end

function load_object(p::ORCaRPaths, digest::AbstractString; limits=Limits())
    result = read_bounded(object_path(p,digest),limits.max_object_bytes)
    isok(result) || return result
    data = unwrap(result)
    hexsha(data)==digest || return fail(Vector{UInt8},OUTCOME_HASH_MISMATCH,"stored object hash mismatch")
    result
end

# -----------------------------------------------------------------------------
# SECTION 04: Integer wire primitives
# -----------------------------------------------------------------------------

function put_uvarint!(io::IO, value::Integer)
    value < 0 && throw(ArgumentError("uvarint cannot encode negative value"))
    v = UInt64(value)
    while v >= 0x80
        write(io,UInt8((v & 0x7f) | 0x80))
        v >>= 7
    end
    write(io,UInt8(v))
end

function get_uvarint(io::IO; maxbytes::Int=10)
    value = UInt64(0)
    shift = 0
    for _ in 1:maxbytes
        eof(io) && throw(EOFError())
        b = read(io,UInt8)
        value |= UInt64(b & 0x7f) << shift
        (b & 0x80)==0 && return value
        shift += 7
    end
    throw(ArgumentError("uvarint exceeds maximum length"))
end

function put_bytes!(io::IO,data::AbstractVector{UInt8})
    put_uvarint!(io,length(data)); write(io,data)
end
function get_bytes(io::IO,limit::Integer)
    n = Int(get_uvarint(io))
    n <= limit || throw(ArgumentError("byte field exceeds limit"))
    length(io.data)-io.ptr+1 >= n || throw(EOFError())
    read(io,n)
end

# -----------------------------------------------------------------------------
# SECTION 05: Strict lossless codecs
# -----------------------------------------------------------------------------

abstract type AbstractLosslessCodec end
struct RawCodec <: AbstractLosslessCodec end
struct RNA5Codec <: AbstractLosslessCodec end
struct BasketCodec <: AbstractLosslessCodec end
struct RLECodec <: AbstractLosslessCodec end
struct TransposeCodec <: AbstractLosslessCodec
    width::Int
end

codec_id(::RawCodec)="raw-v1"
codec_id(::RNA5Codec)="rna5-v1"
codec_id(::BasketCodec)="basket-v1"
codec_id(::RLECodec)="rle-v1"
codec_id(c::TransposeCodec)="transpose-v1-w$(c.width)"

encode(::RawCodec,data::Vector{UInt8})=copy(data)
decode(::RawCodec,data::Vector{UInt8};limit=MAX_DECODED_BYTES_DEFAULT)=
    length(data)<=limit ? copy(data) : throw(ArgumentError("decoded limit exceeded"))

function encode(::RNA5Codec,data::Vector{UInt8})
    length(data) <= typemax(Int)÷3 || throw(ArgumentError("input too large"))
    out = Vector{UInt8}(undef,length(RNA5_PREFIX) + 3 * length(data))
    copyto!(out,1,RNA5_PREFIX,1,length(RNA5_PREFIX))
    digits = codeunits("0123456789ABCDEF")
    p = length(RNA5_PREFIX)+1
    for (i,b) in enumerate(data)
        out[p] = RNA5_STRANDS[mod1(i,5)]
        out[p+1] = digits[Int(b>>4)+1]
        out[p+2] = digits[Int(b&0x0f)+1]
        p += 3
    end
    out
end

function hex_nibble(b::UInt8)
    UInt8('0')<=b<=UInt8('9') && return b-UInt8('0')
    UInt8('A')<=b<=UInt8('F') && return b-UInt8('A')+0x0a
    throw(ArgumentError("invalid uppercase hexadecimal digit"))
end

function decode(::RNA5Codec,data::Vector{UInt8};limit=MAX_DECODED_BYTES_DEFAULT)
    length(data)>=length(RNA5_PREFIX) || throw(ArgumentError("RNA5 header truncated"))
    data[1:length(RNA5_PREFIX)]==RNA5_PREFIX || throw(ArgumentError("RNA5 prefix mismatch"))
    body = length(data)-length(RNA5_PREFIX)
    body%3==0 || throw(ArgumentError("RNA5 body is not a multiple of three"))
    n = body÷3
    n<=limit || throw(ArgumentError("decoded limit exceeded"))
    out = Vector{UInt8}(undef,n)
    p = length(RNA5_PREFIX)+1
    for i in 1:n
        data[p]==RNA5_STRANDS[mod1(i,5)] || throw(ArgumentError("RNA5 strand sequence mismatch at byte $i"))
        out[i] = (hex_nibble(data[p+1])<<4) | hex_nibble(data[p+2])
        p += 3
    end
    out
end

function encode(::BasketCodec,data::Vector{UInt8})
    io=IOBuffer(); write(io,BASKET_MAGIC); put_uvarint!(io,length(data))
    index=1
    while index<=length(data)
        n=min(32,length(data)-index+1)
        write(io,UInt8(mod(div(index-1,32),4)))
        write(io,UInt8(n))
        write(io,@view data[index:index+n-1])
        index+=n
    end
    write(io,sha256(data)); take!(io)
end

function decode(::BasketCodec,data::Vector{UInt8};limit=MAX_DECODED_BYTES_DEFAULT)
    io=IOBuffer(data)
    read(io,length(BASKET_MAGIC))==BASKET_MAGIC || throw(ArgumentError("basket magic mismatch"))
    expected=Int(get_uvarint(io)); expected<=limit || throw(ArgumentError("decoded limit exceeded"))
    expected+length(BASKET_MAGIC)+33 <= length(data) || throw(ArgumentError("basket impossible length"))
    out=UInt8[]; sizehint!(out,expected); cluster=0
    while length(out)<expected
        eof(io) && throw(EOFError())
        polarity=read(io,UInt8); polarity==UInt8(mod(cluster,4)) || throw(ArgumentError("basket polarity sequence mismatch"))
        n=Int(read(io,UInt8)); 1<=n<=32 || throw(ArgumentError("invalid basket chunk size"))
        length(out)+n<=expected || throw(ArgumentError("basket chunk exceeds declared length"))
        append!(out,read(io,n)); cluster+=1
    end
    digest=read(io,32); eof(io) || throw(ArgumentError("basket trailing data"))
    digest==sha256(out) || throw(ArgumentError("basket payload hash mismatch"))
    out
end

function encode(::RLECodec,data::Vector{UInt8})
    io=IOBuffer(); write(io,RLE_MAGIC); put_uvarint!(io,length(data))
    i=1
    while i<=length(data)
        j=i+1
        while j<=length(data) && data[j]==data[i] && j-i<typemax(UInt32)
            j+=1
        end
        run=j-i
        if run>=4
            write(io,UInt8(1)); put_uvarint!(io,run); write(io,data[i]); i=j
        else
            start=i; i+=run
            while i<=length(data)
                k=i+1
                while k<=length(data) && data[k]==data[i] && k-i<typemax(UInt32)
                    k+=1
                end
                k-i>=4 && break
                i=k
                i-start>=65535 && break
            end
            write(io,UInt8(0)); put_uvarint!(io,i-start); write(io,@view data[start:i-1])
        end
    end
    write(io,sha256(data)); take!(io)
end

function decode(::RLECodec,data::Vector{UInt8};limit=MAX_DECODED_BYTES_DEFAULT)
    io=IOBuffer(data)
    read(io,length(RLE_MAGIC))==RLE_MAGIC || throw(ArgumentError("RLE magic mismatch"))
    expected=Int(get_uvarint(io)); expected<=limit || throw(ArgumentError("decoded limit exceeded"))
    out=UInt8[]; sizehint!(out,expected)
    while length(out)<expected
        eof(io) && throw(EOFError())
        tag=read(io,UInt8); n=Int(get_uvarint(io)); n>0 || throw(ArgumentError("zero RLE block"))
        length(out)+n<=expected || throw(ArgumentError("RLE block exceeds declared length"))
        if tag==0
            append!(out,read(io,n))
        elseif tag==1
            eof(io) && throw(EOFError()); append!(out,fill(read(io,UInt8),n))
        else
            throw(ArgumentError("unknown RLE tag"))
        end
    end
    digest=read(io,32); eof(io) || throw(ArgumentError("RLE trailing data"))
    digest==sha256(out) || throw(ArgumentError("RLE payload hash mismatch"))
    out
end

function encode(codec::TransposeCodec,data::Vector{UInt8})
    codec.width>0 || throw(ArgumentError("transpose width must be positive"))
    rows=cld(length(data),codec.width); padded=rows*codec.width
    matrix=fill(UInt8(0),rows,codec.width)
    for i in eachindex(data); matrix[i]=data[i]; end
    payload=vec(permutedims(matrix))
    io=IOBuffer(); write(io,TRANSPOSE_MAGIC); put_uvarint!(io,length(data));
    put_uvarint!(io,codec.width); put_uvarint!(io,rows); write(io,payload); write(io,sha256(data)); take!(io)
end

function decode(::TransposeCodec,data::Vector{UInt8};limit=MAX_DECODED_BYTES_DEFAULT)
    io=IOBuffer(data)
    read(io,length(TRANSPOSE_MAGIC))==TRANSPOSE_MAGIC || throw(ArgumentError("transpose magic mismatch"))
    original=Int(get_uvarint(io)); original<=limit || throw(ArgumentError("decoded limit exceeded"))
    width=Int(get_uvarint(io)); rows=Int(get_uvarint(io))
    width>0 && rows>=0 || throw(ArgumentError("invalid transpose shape"))
    padded=Base.checked_mul(width,rows)
    original<=padded || throw(ArgumentError("original length exceeds padded size"))
    payload=read(io,padded); length(payload)==padded || throw(EOFError())
    transposed=reshape(payload,width,rows)
    matrix=permutedims(transposed)
    flat=vec(matrix); out=flat[1:original]
    digest=read(io,32); eof(io) || throw(ArgumentError("transpose trailing data"))
    digest==sha256(out) || throw(ArgumentError("transpose payload hash mismatch"))
    out
end

struct Candidate
    codec::String
    encoded::Vector{UInt8}
    encoded_sha256::String
    original_sha256::String
    verified::Bool
end

function verify_codec(codec::AbstractLosslessCodec,data::Vector{UInt8};limit=MAX_DECODED_BYTES_DEFAULT)
    encoded=encode(codec,data)
    decoded=decode(codec,encoded;limit=limit)
    decoded==data || throw(ErrorException("roundtrip byte mismatch for $(codec_id(codec))"))
    Candidate(codec_id(codec),encoded,hexsha(encoded),hexsha(data),true)
end

function candidate_arena(data::Vector{UInt8}; widths=(16,32,64,128), limit=MAX_DECODED_BYTES_DEFAULT)
    codecs=AbstractLosslessCodec[RawCodec(),RNA5Codec(),BasketCodec(),RLECodec()]
    append!(codecs,[TransposeCodec(w) for w in widths])
    candidates=Candidate[]
    errors=Dict{String,String}()
    for codec in codecs
        try
            push!(candidates,verify_codec(codec,data;limit=limit))
        catch e
            errors[codec_id(codec)]=sprint(showerror,e)
        end
    end
    isempty(candidates) && return fail(NamedTuple,OUTCOME_ROUNDTRIP_FAILURE,"no codec produced a verified candidate";details=errors)
    sort!(candidates;by=c->(length(c.encoded),c.codec,c.encoded_sha256))
    ok((winner=first(candidates),candidates=candidates,errors=errors))
end

function seal_candidate(p::ORCaRPaths, original_digest::AbstractString;
                        widths=(16,32,64,128), limits=Limits())
    loaded=load_object(p,original_digest;limits=limits)
    isok(loaded) || return fail(Dict{String,Any},loaded.code,loaded.message;details=loaded.details)
    arena=candidate_arena(unwrap(loaded);widths=widths,limit=limits.max_decoded_bytes)
    isok(arena) || return fail(Dict{String,Any},arena.code,arena.message;details=arena.details)
    result=unwrap(arena); winner=result.winner
    stored=store_bytes(p,winner.encoded;declared_name="$original_digest.$(winner.codec)",source="derived:$original_digest")
    isok(stored) || return stored
    meta=unwrap(stored)
    manifest=Dict{String,Any}(
        "format_version"=>FORMAT_VERSION,"original_sha256"=>original_digest,
        "derived_sha256"=>meta["sha256"],"codec"=>winner.codec,
        "encoded_bytes"=>length(winner.encoded),"original_bytes"=>length(unwrap(loaded)),
        "verified"=>true,"created_utc"=>utcnow(),
        "candidate_count"=>length(result.candidates)
    )
    mpath=joinpath(p.derived,original_digest,"$(meta["sha256"]).toml")
    write_toml(mpath,manifest)
    append_event!(HashLedger(p.event_ledger),"candidate.sealed",
      Dict("original"=>original_digest,"derived"=>meta["sha256"],"codec"=>winner.codec))
    ok(manifest)
end

# -----------------------------------------------------------------------------
# SECTION 06: Capability kernel
# -----------------------------------------------------------------------------

struct Capability
    subject::String
    action::String
    resource::String
    issued_utc::DateTime
    expires_utc::DateTime
    nonce::UUID
end

mutable struct CapabilityKernel
    grants::Dict{UUID,Capability}
    revoked::Set{UUID}
    lock::ReentrantLock
end
CapabilityKernel()=CapabilityKernel(Dict{UUID,Capability}(),Set{UUID}(),ReentrantLock())

function grant!(kernel::CapabilityKernel,subject::AbstractString,action::AbstractString,
                resource::AbstractString;ttl::Period=Minute(5))
    nowdt=now(UTC); cap=Capability(String(subject),String(action),String(resource),nowdt,nowdt+ttl,uuid4())
    lock(kernel.lock) do; kernel.grants[cap.nonce]=cap; end
    cap
end
function revoke!(kernel::CapabilityKernel,nonce::UUID)
    lock(kernel.lock) do; push!(kernel.revoked,nonce); end
    nothing
end
function authorised(kernel::CapabilityKernel,cap::Capability,subject::AbstractString,
                    action::AbstractString,resource::AbstractString)
    lock(kernel.lock) do
        haskey(kernel.grants,cap.nonce) || return false
        cap.nonce in kernel.revoked && return false
        now(UTC)<=cap.expires_utc || return false
        cap.subject==subject && cap.action==action && cap.resource==resource
    end
end

# -----------------------------------------------------------------------------
# SECTION 07: Deterministic replay and dependency scheduler
# -----------------------------------------------------------------------------

struct ReplayEvent
    tick::UInt64
    sequence::UInt64
    kind::String
    payload::Vector{UInt8}
    payload_sha256::String
end

function replay_event(tick::Integer,sequence::Integer,kind::AbstractString,payload::Vector{UInt8})
    tick>=0 && sequence>=0 || throw(ArgumentError("negative replay index"))
    ReplayEvent(UInt64(tick),UInt64(sequence),String(kind),copy(payload),hexsha(payload))
end

function write_replay(path::AbstractString,events::Vector{ReplayEvent})
    ordered=sort(events;by=e->(e.tick,e.sequence,e.kind,e.payload_sha256))
    io=IOBuffer(); write(io,codeunits("ORCAR-REPLAY\0")); put_uvarint!(io,FORMAT_VERSION); put_uvarint!(io,length(ordered))
    for e in ordered
        put_uvarint!(io,e.tick); put_uvarint!(io,e.sequence)
        put_bytes!(io,Vector{UInt8}(codeunits(e.kind))); put_bytes!(io,e.payload)
        write(io,hex2bytes(e.payload_sha256))
    end
    body=take!(io); append!(body,sha256(body)); atomic_write(path,body)
end

function read_replay(path::AbstractString;limits=Limits())
    data=unwrap(read_bounded(path,limits.max_object_bytes))
    length(data)>=32 || throw(ArgumentError("replay truncated"))
    body=data[1:end-32]; digest=data[end-31:end]
    sha256(body)==digest || throw(ArgumentError("replay hash mismatch"))
    io=IOBuffer(body); read(io,13)==Vector{UInt8}(codeunits("ORCAR-REPLAY\0")) || throw(ArgumentError("replay magic mismatch"))
    Int(get_uvarint(io))==FORMAT_VERSION || throw(ArgumentError("unsupported replay version"))
    n=Int(get_uvarint(io)); n<=1_000_000 || throw(ArgumentError("event count exceeds limit"))
    events=ReplayEvent[]; sizehint!(events,n)
    previous=(UInt64(0),UInt64(0)); firstevent=true
    for _ in 1:n
        tick=UInt64(get_uvarint(io)); seq=UInt64(get_uvarint(io))
        !firstevent && (tick,seq)<previous && throw(ArgumentError("replay ordering violation"))
        firstevent=false; previous=(tick,seq)
        kind=String(get_bytes(io,4096)); payload=get_bytes(io,limits.max_decoded_bytes); digestbytes=read(io,32)
        sha256(payload)==digestbytes || throw(ArgumentError("event payload hash mismatch"))
        push!(events,replay_event(tick,seq,kind,payload))
    end
    eof(io) || throw(ArgumentError("replay trailing data"))
    events
end

@enum JobState begin JOB_WAITING JOB_RUNNING JOB_SUCCEEDED JOB_FAILED JOB_CANCELLED end
mutable struct Job
    id::String
    dependencies::Vector{String}
    action::Function
    state::JobState
    result::Any
    error::Union{Nothing,String}
end

mutable struct Scheduler
    jobs::Dict{String,Job}
    order::Vector{String}
    cancelled::Set{String}
end
Scheduler()=Scheduler(Dict{String,Job}(),String[],Set{String}())

function add_job!(s::Scheduler,id::AbstractString,deps::Vector{String},action::Function)
    sid=String(id); haskey(s.jobs,sid) && throw(ArgumentError("duplicate job id"))
    s.jobs[sid]=Job(sid,copy(deps),action,JOB_WAITING,nothing,nothing); push!(s.order,sid); sid
end
cancel_job!(s::Scheduler,id::AbstractString)=push!(s.cancelled,String(id))

function validate_graph(s::Scheduler)
    for j in values(s.jobs), dep in j.dependencies
        haskey(s.jobs,dep) || throw(ArgumentError("job $(j.id) depends on absent job $dep"))
    end
    colour=Dict(k=>0 for k in keys(s.jobs))
    function visit(id)
        colour[id]==1 && throw(ArgumentError("dependency cycle at $id"))
        colour[id]==2 && return
        colour[id]=1
        for dep in s.jobs[id].dependencies; visit(dep); end
        colour[id]=2
    end
    for id in sort(collect(keys(s.jobs))); visit(id); end
    true
end

function run!(s::Scheduler)
    validate_graph(s)
    remaining=Set(keys(s.jobs))
    while !isempty(remaining)
        progress=false
        for id in s.order
            id in remaining || continue
            job=s.jobs[id]
            if id in s.cancelled
                job.state=JOB_CANCELLED; delete!(remaining,id); progress=true; continue
            end
            depstates=[s.jobs[d].state for d in job.dependencies]
            if any(x->x in (JOB_FAILED,JOB_CANCELLED),depstates)
                job.state=JOB_CANCELLED; job.error="dependency did not succeed"; delete!(remaining,id); progress=true
            elseif all(==(JOB_SUCCEEDED),depstates)
                job.state=JOB_RUNNING
                try
                    job.result=job.action(); job.state=JOB_SUCCEEDED
                catch e
                    job.error=sprint(showerror,e,catch_backtrace()); job.state=JOB_FAILED
                end
                delete!(remaining,id); progress=true
            end
        end
        progress || throw(ErrorException("scheduler made no progress"))
    end
    s
end

# -----------------------------------------------------------------------------
# SECTION 08: Code graph as byte-grounded relations
# -----------------------------------------------------------------------------

struct GraphNode
    id::String
    kind::String
    object_sha256::String
    byte_start::Int64
    byte_end::Int64
    label::String
end
struct GraphEdge
    source::String
    relation::String
    target::String
    evidence_sha256::String
end
mutable struct CodeGraph
    nodes::Dict{String,GraphNode}
    edges::Vector{GraphEdge}
end
CodeGraph()=CodeGraph(Dict{String,GraphNode}(),GraphEdge[])

function add_node!(g::CodeGraph,node::GraphNode)
    node.byte_start>=0 && node.byte_end>=node.byte_start || throw(ArgumentError("invalid byte range"))
    occursin(r"^[0-9a-f]{64}$",node.object_sha256) || throw(ArgumentError("invalid object hash"))
    haskey(g.nodes,node.id) && g.nodes[node.id]!=node && throw(ArgumentError("node conflict"))
    g.nodes[node.id]=node; node.id
end
function add_edge!(g::CodeGraph,edge::GraphEdge)
    haskey(g.nodes,edge.source) || throw(ArgumentError("missing source node"))
    haskey(g.nodes,edge.target) || throw(ArgumentError("missing target node"))
    push!(g.edges,edge); length(g.edges)
end
function neighbours(g::CodeGraph,id::AbstractString;relation::Union{Nothing,String}=nothing)
    [e for e in g.edges if e.source==id && (relation===nothing || e.relation==relation)]
end

# -----------------------------------------------------------------------------
# SECTION 09: V.A.S.K. and KEYCHAIN numerical laboratory
# -----------------------------------------------------------------------------

struct Sector
    name::String
    basis::Matrix{ComplexF64}
    projector::Matrix{ComplexF64}
    orthonormality_residual::Float64
    hermiticity_residual::Float64
    idempotence_residual::Float64
end

function matrix_residual(a,b)
    norm(a-b) / max(norm(a),norm(b),eps(Float64))
end

function make_sector(name::AbstractString,basis::AbstractMatrix{<:Number}; tolerance=1e-10)
    B=ComplexF64.(basis)
    size(B,1)>0 && size(B,2)>0 || throw(ArgumentError("basis must be non-empty"))
    F=qr(B); Q=Matrix(F.Q)[:,1:size(B,2)]
    rank(B;atol=tolerance)==size(B,2) || throw(ArgumentError("basis is rank deficient"))
    P=Q*Q'
    ortho=matrix_residual(Q'*Q,Matrix{ComplexF64}(I,size(Q,2),size(Q,2)))
    herm=matrix_residual(P,P')
    idem=matrix_residual(P*P,P)
    maximum((ortho,herm,idem))<=100tolerance || throw(ErrorException("sector validation exceeds tolerance"))
    Sector(String(name),Q,P,ortho,herm,idem)
end

struct PermissionOperator
    name::String
    matrix::Matrix{ComplexF64}
    weights::Dict{String,Float64}
    hermiticity_residual::Float64
    idempotence_residual::Float64
    is_projector::Bool
end

function permission_operator(name::AbstractString,sectors::Dict{String,Sector},weights::Dict{String,<:Real};tolerance=1e-10)
    isempty(weights) && throw(ArgumentError("weights are empty"))
    dims=unique(size(sectors[k].projector,1) for k in keys(weights))
    length(dims)==1 || throw(ArgumentError("sector dimensions differ"))
    n=first(dims); M=zeros(ComplexF64,n,n)
    normalised=Dict{String,Float64}()
    for (k,w0) in weights
        haskey(sectors,k) || throw(ArgumentError("unknown sector $k"))
        w=Float64(w0); isfinite(w) || throw(ArgumentError("non-finite weight"))
        M .+= w .* sectors[k].projector; normalised[k]=w
    end
    herm=matrix_residual(M,M'); idem=matrix_residual(M*M,M)
    PermissionOperator(String(name),M,normalised,herm,idem,herm<=tolerance && idem<=tolerance)
end

function normalise_state(psi::AbstractVector{<:Number})
    x=ComplexF64.(psi); n=norm(x); n>0 || throw(ArgumentError("zero state")); x/n
end

function activation(psi::AbstractVector{<:Number},sector::Sector;tolerance=1e-10)
    x=normalise_state(psi); length(x)==size(sector.projector,1) || throw(DimensionMismatch())
    a=real(dot(x,sector.projector*x))
    -tolerance<=a<=1+tolerance || throw(ErrorException("activation outside projector range"))
    clamp(a,0.0,1.0)
end

effective_coupling(g0::Real,weight::Real,alpha::Real)=Float64(g0)*Float64(weight)*Float64(alpha)
landau_potential(alpha::Real,mu::Real,teff::Real,d::Real,r::Real,u::Real)=
    -mu*alpha + 0.5*(teff*d-r)*alpha^2 + 0.25*u*alpha^4
landau_gradient(alpha::Real,mu::Real,teff::Real,d::Real,r::Real,u::Real)=
    -mu + (teff*d-r)*alpha + u*alpha^3

function unitary_step(psi::AbstractVector{<:Number},H::AbstractMatrix{<:Number},dt::Real;hbar::Real=1.0,tolerance=1e-10)
    x=normalise_state(psi); A=ComplexF64.(H)
    size(A,1)==size(A,2)==length(x) || throw(DimensionMismatch())
    matrix_residual(A,A')<=tolerance || throw(ArgumentError("Hamiltonian is not Hermitian"))
    F=eigen(Hermitian(A)); y=F.vectors*(exp.(-im*Float64(dt)/Float64(hbar).*F.values).*(F.vectors'*x))
    normalise_state(y)
end

function zgate_cycle(vector::AbstractVector, power::Integer=1)
    n=length(vector); n>0 || return copy(vector)
    p=mod(power,3)
    p==0 && return copy(vector)
    groups=cld(n,3); out=similar(vector)
    for g in 0:groups-1
        idx=[i for i in (3g+1):(3g+3) if i<=n]
        for (j,i) in enumerate(idx)
            out[i]=vector[idx[mod1(j-p,length(idx))]]
        end
    end
    out
end

struct RotaNode
    id::String
    label::String
end
struct RotaEdge
    source::String
    gate::String
    target::String
    inverse_gate::String
end
struct RotaGraph
    nodes::Dict{String,RotaNode}
    edges::Vector{RotaEdge}
end

function default_rota_graph()
    labels=Dict("+Z"=>"House 1","-Z"=>"House 0","-X"=>"Anti West","+X"=>"Grounded East",
                "+Y"=>"Grounded Upper","-Y"=>"Anti Lower","0Z"=>"Mirror","V0"=>"F1 Buffer West","V1"=>"F1 Buffer East")
    nodes=Dict(k=>RotaNode(k,v) for (k,v) in labels)
    edges=RotaEdge[
        RotaEdge("0Z","north","+Z","south"),RotaEdge("+Z","south","0Z","north"),
        RotaEdge("0Z","south","-Z","north"),RotaEdge("-Z","north","0Z","south"),
        RotaEdge("0Z","west","-X","east"),RotaEdge("-X","east","0Z","west"),
        RotaEdge("0Z","east","+X","west"),RotaEdge("+X","west","0Z","east"),
        RotaEdge("+Z","upper","+Y","lower"),RotaEdge("+Y","lower","+Z","upper"),
        RotaEdge("-Z","lower","-Y","upper"),RotaEdge("-Y","upper","-Z","lower"),
        RotaEdge("-X","buffer","V0","return"),RotaEdge("V0","return","-X","buffer"),
        RotaEdge("+X","buffer","V1","return"),RotaEdge("V1","return","+X","buffer")]
    RotaGraph(nodes,edges)
end

function rota_transition(g::RotaGraph,current::AbstractString,gate::AbstractString)
    matches=[e for e in g.edges if e.source==current && e.gate==gate]
    length(matches)==1 || throw(ArgumentError(isempty(matches) ? "transition absent" : "transition ambiguous"))
    first(matches).target
end

# -----------------------------------------------------------------------------
# SECTION 10: Capsule transport
# -----------------------------------------------------------------------------

function collect_capsule_files(p::ORCaRPaths)
    roots=[p.objects,p.metadata,p.derived,p.ledgers,p.checkpoints,p.extensions,p.research]
    files=String[]
    for root in roots
        isdir(root) || continue
        for (dir,_,names) in walkdir(root)
            for name in names
                full=joinpath(dir,name); islink(full) && continue; isfile(full) || continue
                push!(files,relpath(full,p.root))
            end
        end
    end
    sort!(unique!(files))
end

function make_capsule(p::ORCaRPaths,destination::AbstractString)
    files=collect_capsule_files(p)
    manifest_files=[Dict("path"=>replace(f,'\\'=>'/'),"bytes"=>filesize(joinpath(p.root,f)),
                         "sha256"=>file_sha256(joinpath(p.root,f))) for f in files]
    manifest=Dict{String,Any}("format_version"=>FORMAT_VERSION,"program_version"=>string(VERSION),
        "created_utc"=>utcnow(),"root_identity"=>hexsha(Vector{UInt8}(codeunits(p.root))),"files"=>manifest_files)
    staging=mktempdir(p.tmp;prefix="capsule-")
    try
        for f in files
            safe=checked_relpath(f); target=joinpath(staging,safe); mkpath(dirname(target)); cp(joinpath(p.root,f),target;force=true,follow_symlinks=false)
        end
        write_toml(joinpath(staging,CAPSULE_MANIFEST),manifest)
        Tar.create(staging,destination)
        digest=file_sha256(destination)
        append_event!(HashLedger(p.event_ledger),"capsule.created",Dict("path"=>abspath(destination),"sha256"=>digest,"files"=>string(length(files))))
        return ok(Dict("path"=>abspath(destination),"sha256"=>digest,"files"=>length(files)))
    catch e
        return fail(Dict{String,Any},OUTCOME_IO_ERROR,sprint(showerror,e))
    finally
        isdir(staging) && rm(staging;recursive=true,force=true)
    end
end

# Extraction is deliberately transactional: Tar lists and extracts into quarantine,
# every manifest path is validated, every byte hash is checked, and only then are
# immutable objects copied into the live root.
function import_capsule(p::ORCaRPaths,capsule::AbstractString;limits=Limits())
    filesize(capsule)<=limits.max_archive_bytes || return fail(Dict{String,Any},OUTCOME_LIMIT_EXCEEDED,"capsule exceeds byte limit")
    staging=mktempdir(p.quarantine;prefix="capsule-import-")
    try
        Tar.extract(capsule,staging)
        mpath=joinpath(staging,CAPSULE_MANIFEST)
        isfile(mpath) || return fail(Dict{String,Any},OUTCOME_FORMAT_ERROR,"capsule manifest absent")
        manifest=TOML.parsefile(mpath)
        get(manifest,"format_version",0)==FORMAT_VERSION || return fail(Dict{String,Any},OUTCOME_FORMAT_ERROR,"unsupported capsule version")
        entries=get(manifest,"files",Any[])
        length(entries)<=limits.max_archive_entries || return fail(Dict{String,Any},OUTCOME_LIMIT_EXCEEDED,"capsule entry count exceeds limit")
        total=Int64(0)
        for entry in entries
            rel=checked_relpath(entry["path"]); full=joinpath(staging,rel)
            isfile(full) && !islink(full) || return fail(Dict{String,Any},OUTCOME_FORMAT_ERROR,"capsule member is absent or non-regular";details=Dict("path"=>rel))
            bytes=filesize(full); total=Base.checked_add(total,bytes)
            total<=limits.max_archive_bytes || return fail(Dict{String,Any},OUTCOME_LIMIT_EXCEEDED,"expanded capsule exceeds limit")
            bytes==entry["bytes"] || return fail(Dict{String,Any},OUTCOME_HASH_MISMATCH,"capsule size mismatch";details=Dict("path"=>rel))
            file_sha256(full)==entry["sha256"] || return fail(Dict{String,Any},OUTCOME_HASH_MISMATCH,"capsule hash mismatch";details=Dict("path"=>rel))
        end
        imported=0
        for entry in entries
            rel=checked_relpath(entry["path"])
            if startswith(rel,"objects/")
                data=read(joinpath(staging,rel)); r=store_bytes(p,data;declared_name=basename(rel),source="capsule:$(abspath(capsule))")
                isok(r) || return r; imported+=1
            end
        end
        append_event!(HashLedger(p.event_ledger),"capsule.imported",Dict("path"=>abspath(capsule),"objects"=>string(imported)))
        return ok(Dict("verified_entries"=>length(entries),"imported_objects"=>imported,"expanded_bytes"=>total))
    catch e
        return fail(Dict{String,Any},OUTCOME_FORMAT_ERROR,sprint(showerror,e))
    finally
        isdir(staging) && rm(staging;recursive=true,force=true)
    end
end

# -----------------------------------------------------------------------------
# SECTION 11: Optional Julia extension gate
# -----------------------------------------------------------------------------

struct ExtensionStatus
    name::String
    available::Bool
    loaded::Bool
    version::String
    message::String
end

function extension_status(name::AbstractString)
    available=Base.find_package(String(name))!==nothing
    ExtensionStatus(String(name),available,false,"",available ? "available but not loaded" : "not installed")
end

function load_extension(name::AbstractString)
    allowed=Set(["JSON3","HTTP","SQLite","CodecZstd","StructTypes"])
    String(name) in allowed || throw(ArgumentError("extension not allow-listed"))
    Base.find_package(String(name))===nothing && return ExtensionStatus(String(name),false,false,"","not installed")
    try
        Base.eval(@__MODULE__,Expr(:using,Symbol(name)))
        m=getfield(@__MODULE__,Symbol(name))
        ver=try string(Base.pkgversion(m)) catch; "unknown" end
        ExtensionStatus(String(name),true,true,ver,"loaded")
    catch e
        ExtensionStatus(String(name),true,false,"",sprint(showerror,e))
    end
end

function julia_package_commands()
    [
      "julia --project=. -e 'using Pkg; Pkg.activate(\".\"); Pkg.instantiate()'",
      "julia --project=. -e 'using Pkg; Pkg.add([\"JSON3\",\"HTTP\",\"SQLite\",\"CodecZstd\",\"StructTypes\"])'",
      "julia --project=. -e 'using Pkg; Pkg.precompile()'",
      "julia --project=. ORCaRzGate.jl selftest"
    ]
end

# -----------------------------------------------------------------------------
# SECTION 12: Complete verification
# -----------------------------------------------------------------------------

function verify_store(p::ORCaRPaths;limits=Limits())
    checked=0; failures=String[]
    if isdir(p.objects)
        for (dir,_,names) in walkdir(p.objects)
            for name in names
                occursin(r"^[0-9a-f]{64}$",name) || continue
                full=joinpath(dir,name)
                try
                    filesize(full)<=limits.max_object_bytes || throw(ArgumentError("object exceeds limit"))
                    file_sha256(full)==name || throw(ArgumentError("hash mismatch"))
                    checked+=1
                catch e
                    push!(failures,"$name: $(sprint(showerror,e))")
                end
            end
        end
    end
    ledger=verify_ledger(HashLedger(p.event_ledger))
    isok(ledger) || push!(failures,"ledger: $(ledger.message)")
    isempty(failures) ? ok((objects=checked,ledger=isok(ledger) ? unwrap(ledger) : nothing)) :
        fail(NamedTuple,OUTCOME_HASH_MISMATCH,"store verification failed";details=Dict(string(i)=>x for (i,x) in enumerate(failures)))
end

function selftest(;verbose=true)
    tests=Pair{String,Function}[]
    push!(tests,"varint"=>()->begin
        for n in UInt64[0,1,127,128,255,256,65535,typemax(UInt32),typemax(UInt64)]
            io=IOBuffer(); put_uvarint!(io,n); seekstart(io); get_uvarint(io)==n || error("varint mismatch")
        end
    end)
    push!(tests,"codecs"=>()->begin
        fixtures=[UInt8[],collect(UInt8(0):UInt8(255)),fill(UInt8(0xaa),10000),rand(MersenneTwister(8),UInt8,65537)]
        codecs=AbstractLosslessCodec[RawCodec(),RNA5Codec(),BasketCodec(),RLECodec(),TransposeCodec(31)]
        for fixture in fixtures, codec in codecs
            decode(codec,encode(codec,fixture);limit=max(length(fixture),1))==fixture || error("codec mismatch")
        end
    end)
    push!(tests,"arena"=>()->begin
        data=repeat(Vector{UInt8}(codeunits("ORCaR-Z-Gate")),1000)
        r=candidate_arena(data); isok(r) || error(r.message); unwrap(r).winner.verified || error("unverified winner")
    end)
    push!(tests,"ledger"=>()->begin
        mktempdir() do d
            l=HashLedger(joinpath(d,"events.log")); append_event!(l,"a",Dict("x"=>"1")); append_event!(l,"b",Dict("x"=>"2"));
            v=verify_ledger(l); isok(v) || error(v.message); unwrap(v).records==2 || error("ledger count")
        end
    end)
    push!(tests,"object_store"=>()->begin
        mktempdir() do d
            p=init_root(d); r=store_bytes(p,UInt8[0,1,2,3];declared_name="x.bin"); isok(r) || error(r.message)
            digest=unwrap(r)["sha256"]; unwrap(load_object(p,digest))==UInt8[0,1,2,3] || error("load mismatch")
            isok(verify_store(p)) || error("verify failed")
        end
    end)
    push!(tests,"replay"=>()->begin
        mktempdir() do d
            path=joinpath(d,"r.orcr"); ev=[replay_event(2,0,"b",UInt8[2]),replay_event(1,0,"a",UInt8[1])]
            write_replay(path,ev); x=read_replay(path); x[1].tick==1 && x[2].tick==2 || error("replay order")
        end
    end)
    push!(tests,"scheduler"=>()->begin
        s=Scheduler(); seen=String[]; add_job!(s,"a",String[],()->push!(seen,"a")); add_job!(s,"b",["a"],()->push!(seen,"b")); run!(s)
        seen==["a","b"] || error("scheduler order")
    end)
    push!(tests,"capabilities"=>()->begin
        k=CapabilityKernel(); c=grant!(k,"agent","read","object:abc"); authorised(k,c,"agent","read","object:abc") || error("grant failed"); revoke!(k,c.nonce); !authorised(k,c,"agent","read","object:abc") || error("revoke failed")
    end)
    push!(tests,"vask"=>()->begin
        B=Matrix{Float64}(I,8,8)[:,1:3]; s=make_sector("S",B); abs(s.idempotence_residual)<1e-10 || error("projector")
        psi=normalise_state(ones(ComplexF64,8)); a=activation(psi,s); 0<=a<=1 || error("activation")
        zgate_cycle([1,2,3],3)==[1,2,3] || error("z gate")
    end)
    failures=Dict{String,String}(); passed=0
    for (name,f) in tests
        try f(); passed+=1; verbose && println("PASS ",name)
        catch e; failures[name]=sprint(showerror,e,catch_backtrace()); verbose && println("FAIL ",name,": ",failures[name]) end
    end
    isempty(failures) ? ok((passed=passed,total=length(tests))) :
        fail(NamedTuple,OUTCOME_INTERNAL_ERROR,"selftest failures";details=failures)
end

# -----------------------------------------------------------------------------
# SECTION 13: CLI
# -----------------------------------------------------------------------------

function usage(io::IO=stdout)
    println(io,"ORCaRzGate.jl ",VERSION)
    println(io,"Commands:")
    println(io,"  init ROOT")
    println(io,"  admit ROOT FILE")
    println(io,"  seal ROOT SHA256")
    println(io,"  scan FILE")
    println(io,"  verify ROOT")
    println(io,"  capsule ROOT OUTPUT.tar")
    println(io,"  import ROOT INPUT.tar")
    println(io,"  rna5-encode INPUT OUTPUT")
    println(io,"  rna5-decode INPUT OUTPUT")
    println(io,"  selftest")
    println(io,"  packages")
end

function print_toml(d)
    TOML.print(stdout,d isa AbstractDict ? d : Dict("result"=>string(d));sorted=true); println()
end

function outcome_exit(o::Outcome)
    if isok(o)
        v=unwrap(o)
        if v isa AbstractDict; print_toml(v)
        elseif v isa NamedTuple; print_toml(Dict(string(k)=>string(getfield(v,k)) for k in keys(v)))
        else println(v) end
        return 0
    else
        println(stderr,"ERROR ",Int(o.code)," ",o.message)
        for (k,v) in sort(collect(o.details);by=first); println(stderr,"  ",k,": ",v); end
        return Int(o.code)==0 ? 1 : min(Int(o.code),125)
    end
end

function main(args=ARGS)
    isempty(args) && (usage(); return 0)
    cmd=args[1]
    try
        if cmd=="init" && length(args)==2
            p=init_root(args[2]); println(p.root); return 0
        elseif cmd=="admit" && length(args)==3
            return outcome_exit(admit_file(paths(args[2]),args[3]))
        elseif cmd=="seal" && length(args)==3
            return outcome_exit(seal_candidate(paths(args[2]),args[3]))
        elseif cmd=="scan" && length(args)==2
            r=read_bounded(args[2],MAX_OBJECT_BYTES_DEFAULT); isok(r) || return outcome_exit(r)
            print_toml(scan_bytes(unwrap(r);declared_name=basename(args[2]))); return 0
        elseif cmd=="verify" && length(args)==2
            return outcome_exit(verify_store(paths(args[2])))
        elseif cmd=="capsule" && length(args)==3
            return outcome_exit(make_capsule(paths(args[2]),args[3]))
        elseif cmd=="import" && length(args)==3
            return outcome_exit(import_capsule(paths(args[2]),args[3]))
        elseif cmd=="rna5-encode" && length(args)==3
            data=unwrap(read_bounded(args[2],MAX_OBJECT_BYTES_DEFAULT)); atomic_write(args[3],encode(RNA5Codec(),data)); return 0
        elseif cmd=="rna5-decode" && length(args)==3
            data=unwrap(read_bounded(args[2],MAX_TOKEN_BYTES_DEFAULT)); atomic_write(args[3],decode(RNA5Codec(),data)); return 0
        elseif cmd=="selftest" && length(args)==1
            return outcome_exit(selftest())
        elseif cmd=="packages" && length(args)==1
            foreach(println,julia_package_commands()); return 0
        else
            usage(stderr); return 2
        end
    catch e
        println(stderr,"FATAL ",sprint(showerror,e,catch_backtrace()))
        return 70
    end
end

export VERSION, Outcome, OutcomeCode, ORCaRPaths, Limits, paths, init_root,
       scan_bytes, admit_file, store_bytes, load_object, verify_store,
       RawCodec, RNA5Codec, BasketCodec, RLECodec, TransposeCodec,
       encode, decode, verify_codec, candidate_arena, seal_candidate,
       HashLedger, append_event!, verify_ledger,
       Capability, CapabilityKernel, grant!, revoke!, authorised,
       ReplayEvent, replay_event, write_replay, read_replay,
       Scheduler, Job, add_job!, cancel_job!, run!,
       CodeGraph, GraphNode, GraphEdge, add_node!, add_edge!, neighbours,
       Sector, PermissionOperator, make_sector, permission_operator,
       normalise_state, activation, effective_coupling, landau_potential,
       landau_gradient, unitary_step, zgate_cycle,
       RotaNode, RotaEdge, RotaGraph, default_rota_graph, rota_transition,
       make_capsule, import_capsule,
       ExtensionStatus, extension_status, load_extension, julia_package_commands,
       selftest, main

end # module ORCaRzGate

if abspath(PROGRAM_FILE) == @__FILE__
    exit(ORCaRzGate.main())
end
