PHAROS DATA ARK · 2026-10-29-01024f5b59
Content types and handler API v1
Purpose and current scope
config/content-types.yaml is the single registry for restoration types. Handlers
shipped with the Ark and handlers added later use exactly the same declaration,
loader, context and result contract. There is no native/plugin flag or alternate
execution path. Python supplies mechanisms; configuration chooses a handler and
its options. This interface currently integrates the restoration queue, not every
scheduled updater or content-management endpoint.
The existing collection installers are reached through a compatibility adapter.
Their collection-specific internals have not all been converted to configuration.
They advertise only restore; do not infer support for removal or standalone
verification. File downloads use the established resumable, verified downloader.
The queue retains its existing reader publication steps after archive restoration.
Register a type
schema: 1
types:
example-text:
api: 1
handler: plugins/example_text.py
operations: [restore, inspect, verify]
options: {}
The file is UTF-8 YAML. All four fields are required. Unknown fields, duplicate
keys, unsupported versions and unknown operations are rejected. handler names
an existing .py file inside the trusted source repository; absolute paths,
traversal and symlink escapes are rejected. options is a mapping whose fields
and defaults the handler documents and validates. No shell command strings or
inline Python are evaluated from YAML.
Reference a registered type in config/content/content.yaml:
recipes:
- id: local-welcome
type: example-text
enabled: true
path: welcome.txt
text: Welcome to the Data Ark
installed_bytes: 4096
temporary_bytes: 4096
update_headroom_bytes: 4096
id uniquely identifies the collection; type identifies its handler. Older
recipes without type use their id as the type name. Existing file groups
archives, direct_files and map_files select those registered type names.
Capacity estimates are bytes, conservative and caretaker-reviewed. Unknown bounds
block queue approval. requires lists collection IDs, not type names; the queue
orders dependencies and detects missing/cyclic dependencies.
Python interface
Each module declares API_VERSION = 1 and implements:
def validate(item, context):
# Raise ValueError for invalid fields. No downloads or writes here.
...
def restore(item, context):
...
return {"status": "complete", "message": "Installed and verified"}
Every declared operation takes (item, context); validate runs first on every
dispatch. item is the collection mapping from the reviewed recipe. Do not mutate
it or context.profile. Context fields:
| Field/method | Meaning |
| --- | --- |
| content_root | Destination drive as a Path |
| profile | Reviewed restoration profile, including reserve/rate settings |
| profile_folder | Directory containing the recipe and portable snapshots |
| options | A copy of this type's registry options |
| target(relative) | Resolve a relative content path; reject escapes |
| checkpoint(phase) | Check cooperative cancellation, then emit a short phase |
| progress(phase) | Progress callback; prefer checkpoint |
| cancelled() | Whether cooperative cancellation is requested |
The existing queue also stops the worker process group on pause/cancel and records
interruption persistently. Legacy recipe adapters currently report coarse phases;
they do not promise fine-grained progress or cooperative cancellation internally.
Do not daemonize children or escape that process group.
Operations and results
| Operation | Required behavior |
| --- | --- |
| restore | Reuse verified existing content; otherwise acquire, verify, then publish |
| inspect | Read-only presence/state inspection |
| verify | Read-only integrity checks; raise on corruption |
| update | Apply the configured source/edition policy, preserving the previous usable copy until verified |
| remove | Remove only owned collection files; retain desired-state/source information for reinstatement |
Declare only operations actually implemented. Unsupported operations fail before
the handler is imported. No UI removal endpoint is automatically exposed by adding
remove. Caretaker authorization and confirmation belong to the calling service.
Return a dictionary with status (complete, present, or missing) and a
human-readable message. missing is useful for inspection; it fails mutating
operations rather than marking a failed install complete. Additional result fields
may be supplied but are not currently consumed by the queue. Raise ValueError
for invalid configuration/integrity, RuntimeError for operational failure, or
InterruptedError for cooperative cancellation. The queue records failure and
keeps the job resumable. Do not log passwords, tokens or private file contents.
Reliability and dependencies
Handlers must be idempotent: repeating work after an interruption must not damage
existing content. Download to staging, enforce capacity/rate limits, check sizes,
hashes and format, then atomically publish on the same filesystem. Never replace
the only usable copy before verification. Resume safely or restart staging work;
document which behavior is supported. Cleanly report missing executables or Python
packages. This version does not install dependencies automatically: document and
provision them during appliance setup, using pinned/reviewed versions as practical.
The example uses only the standard library.
Use the existing shared content lock; handlers must not acquire a conflicting
second lock or circumvent the queue's capacity checks. Lifecycle hooks run with
the worker's permissions, potentially root. This is not a Python sandbox.
Trust, portability and recovery
Installing or editing handler code is caretaker/local-administrator work. The web
public-manifest editor does not upload Python or edit this executable registry.
Inspect source before approving a queue. Registry reads validate structure without
importing modules; loading a Python module executes its top-level statements.
Portable configuration bundles include the registry and every declared handler
file. Queue fingerprints include their bytes: changing either invalidates an
existing approval. Keep helper modules/dependencies with the matching source
repository; arbitrary dependency trees are not discovered or bundled automatically.
Never put secrets in handler options or portable files. These additions do not
make recovery dependable until spare-media acceptance tests pass.
Conformance and example
From the source repository, using the Ark Python environment:
python tools/check_content_types.py
python -m unittest tests.test_content_types
The checker imports reviewed modules and checks API versions and callable
signatures. It does not invoke lifecycle operations and cannot establish safety,
correctness or dependency availability. The tests exercise plugins/example_text.py
in a temporary directory, including restore/reuse, verification, cancellation and
invalid inputs. Use that file as a working template, not as proof that an arbitrary
new handler is correct. Add fixture tests for failures, interrupted acquisition,
capacity exhaustion and source changes; then test on spare media.
An incompatible contract change requires a new API version and explicit migration.
Do not silently reinterpret an existing version's inputs or results.