1.2.0-rc.1 / Evidence and duties

Agent duties

Execute supported attribution, retention and reporting duties explicitly.

This component performs local operations under a verified free agreement: it retrieves delivered bytes, writes and deletes managed copies, and submits separate reports. It demonstrates the selected duties described below; it is not a claim of full Agent Core conformance.

Responsibility and API

clients/duty_executor.mjs uses native Node APIs. Its caller must first authenticate discovery, authority, exact offer and terms, signed acceptance receipt, active access authorisation and the delivered representation. The executor does not grant permission, verify those cryptographic objects or perform HTTP requests. Supplying an unverified offer defeats that trust boundary.

const executor = await DutyExecutor.open({
  offer,                         // Exact, already verified free offer
  agreementId: receipt.agreement_id,
  reporterId,
  storageDir,                    // Private durable journal + disposable asset cache
  useExpiresAt: receipt.use_expires_at,
  clock: { now, setTimeout, clearTimeout }, // Optional; epoch milliseconds
  retryDelayMs: 1000,
  reportAttemptTimeoutMs: 5000,
  sendReport                     // Authenticated transport/verification adapter
});
const acquired = await executor.retrieved({ resourceUrl, bytes, assetRef });
const stored = await executor.store(acquired);
const copy = await executor.copy(stored);
await executor.flush();
const progress = executor.progress();
await executor.close();

Handles contain id, resourceUrl, assetRef, acquiredAt and expiresAt; stored handles also contain path. Times are epoch milliseconds, with null for no finite expiry. The caller must stop dependent work on rejected operations or progress errors. Methods accept managed handles, not arbitrary disk paths.

The reporting adapter receives sendReport(endpoint, {event, bytes}). It must authorise that exact collector, sign the exact bytes, send them and verify the signed intake against independently trusted authority and the original report. It returns {verified: true, eventDigest, receivedAt, reporterId} only after verification. This is an internal adapter contract, not a new Odexa wire format. Unit tests inject this adapter; the TLS harness uses real signed reports and collector responses.

Implemented behaviour

  • Only offered retrieve and store actions execute. Unknown duties, unoffered resources and purposes, model training/fine-tuning, and irreversible operations with finite retention are refused. operationSupported is a capability check, not permission to perform some separate operation.
  • Retention uses the shortest applicable interval and the earlier agreement use expiry. Managed copies preserve their original acquisition time and deadline; copying never renews either. Acquisition is when retrieved registers the observed bytes. Callers must invoke it promptly after retrieval, not use delayed registration to renew an earlier copy.
  • Storage and copying write real files. The component removes expired files and zeros its retained input buffer. Zero retention prohibits disk writes. Expiration runs independently of a slow reporting request, and access checks reject expired handles even before a timer callback executes.
  • Each actual registered retrieval and successful file write generates one use.reported event with its own operation ID and the verified agreement ID. Report transport retries preserve the exact payload bytes and event ID. This implementation describes a completed write, not proof that a remote system continues to retain the asset.
  • Multiple reporting endpoints each receive the event; overlapping duties for one endpoint use the shortest deadline. Deadlines use the serialised completion timestamp. Pending, reported, missed and late are distinct local states. An unavailable collector does not count as reported. Overdue required reporting blocks further dependent use.
  • A lost acknowledgement may be recovered after the deadline if the original verified intake shows timely receipt. A truly late receipt remains late. A wrong digest, wrong authenticated reporter or unverified acknowledgement does not clear the duty.
  • renderAttributed(text) appends every distinct required name and source URL to plain-text output. It is a usable output fixture; it does not establish that an end user saw attribution or grant transformation/redistribution rights.
  • Graceful close deletes managed asset content even before expiry and preserves the reporting journal. Reopening purges disposable asset files while retaining their original acquisition/expiry history and every report. Old handles do not become usable again. Unknown files, symlink roots and non-regular or unsafe-permission entries are rejected.

Restart-safe local reporting

The private directory contains .odexa-duty-journal.json, an ownership marker and a live-owner lock. Asset files remain disposable; the directory and journal are not disposable while duties or audit retention remain outstanding. Reopen the same directory with the same verified offer object, agreement ID, reporter ID and use expiry. Binding uses the serialized supplied offer object, so callers must preserve its original member/array ordering as well as its values. A different grant or corrupt/missing journal requires explicit recovery; opening does not silently reset evidence.

Before a managed operation, the executor durably records its intent, stable operation/event IDs, acquisition time and original retention deadline. After observing a successful local operation it atomically records completion together with every required report’s exact payload bytes, endpoint and deadline, before returning success. Before transmission it persists the attempt; after authenticating an intake it persists the outcome and collector receipt time. pending, reported, missed and late survive restart. A lost acknowledgement retries the original bytes and IDs; it cannot create a new completed use or extend its reporting deadline.

The journal is written to a new private temporary file, flushed, atomically renamed and followed by a directory flush. Managed asset writes are flushed before their completion is recorded. This provides a local filesystem durability boundary, not a hardware guarantee. An intent left without durable completion is recovered as uncertain, with no fabricated completed report; dependent use stays blocked pending reconciliation. A crash can interrupt the gap between physical write and journal completion, so claiming exactly-once physical execution would be inaccurate.

Restored outcomes are local records of results previously verified by the trusted adapter. They do not independently authenticate collector delivery: the journal’s checksum detects corruption, not an attacker who controls the same OS account. The reporting adapter must still verify any new or retried intake. The journal does not contain a portable signed-receipt export and cannot upgrade client_reported evidence to an independently observed downstream fact.

The directory must be owned by the current user with no group/other permissions; files must be private, regular and not hard-linked elsewhere. A PID lock rejects a second live executor; an exited process’s lock can be recovered. Every opener must first acquire an exclusive .odexa-duty-recovery-guard, so concurrent reclaimers cannot unlink each other’s newly created owner lock. A guard abandoned by a crash is never automatically reclaimed: explicit recovery must establish that every opener/executor has stopped before removing only that guard, preserving the journal and cache for normal validated recovery. PID reuse fails conservatively. Protect parent paths, backups and this directory from concurrent local mutation. This is a single-host component, not a distributed lock or a sandbox against a hostile process with the same user privileges. Journal capacity is bounded to 16 MiB and 10,000 operations; reaching capacity fails closed instead of discarding history. A legacy cache without a journal is not silently migrated.

The default clock advances from a wall-clock starting point using monotonic elapsed time. Injected clocks must never move backwards. Filesystem deletion is logical deletion of managed paths, not secure erasure from storage media, backups, snapshots, other processes or model weights. Runtime suspension, power loss and failed deletion require operational handling; a timer alone cannot promise physical erasure at an exact instant.

Executed validation

Run from the candidate root:

node --test verification/test_duty_executor.mjs

The 28 passing tests cover actual bytes and permissions, acquisition-preserving copies, expiry/zero retention, overdue/late reporting, acknowledgement binding failures, expiry during a hung transport or slow durable-intent write, combined duties, attribution, unsupported operations, use expiry/backwards clocks, restart cache disposal and unsafe storage inputs. Restart cases check exact-byte pending retries, previously verified outcomes, missing reports, changed retention/transaction bindings and corrupted journals. Three tests actually exit a child process before acknowledgement, after a simulated collector commit with a lost acknowledgement, and after file write before durable completion. A deterministic concurrency test pauses one stale-lock reclaimer immediately after reading the old owner, overlaps a second opener and checks that only the first can acquire ownership; another checks that an abandoned recovery guard is preserved. These tests use controlled time and injected reporting adapters; they do not simulate power loss or real collector HTTP during restart.

The separate clients/duty_demo.mjs / odexa_ref/duty_demo.py harness previously completed a real local TLS free agreement with certificate verification enabled. Its eight-check report in verification/duty-run/ covers three verified report intakes, an identical lost-acknowledgement retry and deletion of both real managed files under controlled expiry. That historical saved run predates this journal addition. The current-source nine-check reconstruction run is described below. The retention clock is accelerated, not a 600-second wall-clock endurance test. This is internal implementation evidence, not independent external certification.

Current boundaries and remaining integration

  1. Operational recovery and portable evidence. This legacy executor has durable local retry and the real TLS reconstruction evidence below. The newer selected-storage executor also has actual abrupt-process cases, signed collection and closed ordinary/asset free archives, as described in storage integration. Neither result turns this local journal into an independent signed archive or proves abrupt-process recovery against a real collector for every duty. Do not delete the journal to clear a missed duty. Cache disposal alone does not discharge a reporting obligation.
  2. Continuous storage lifecycle. The separate storage-session contract now defines completed writes and continuing custody as distinct operations, with start, daily checkpoints, cessation, exact parent references and metric accounting. Signed selection, actual disk/memory execution and selected free archives are implemented in the current integration. This older executor is not silently upgraded to that wire profile. Selected paid archives are now implemented under paid portability; final independent coverage remains open.
  3. Broader agent duties and lifecycle. Managed retrieve/store does not implement arbitrary transform, redistribution or training. The reference must decline uses whose duties it cannot execute; it need not build a model trainer to support policy vocabulary. Caller input buffers and copies outside this directory remain outside its custody. The provider handover procedure preserves original accepted deadlines and separately qualifies a limited reporting tail. Current-profile duty/installation guidance remains required under the fixed completion plan; additional capabilities must execute every applicable duty or decline that use. Revocation’s accepted future-access rule does not imply an unagreed new deletion duty.
  4. Truth and measurement. An authenticated report remains a client’s assertion. This fixture observes its own files and operations; it cannot prove another client’s honesty, universal downstream tracking or model unlearning. The earlier deliberately false-report integration test remains intact and useful. Reporting accuracy, collector intake and observed delivery must remain separate evidence categories.

These outstanding items preserve the full protocol goal. They are not reasons to claim that the narrower demonstration is the finished protocol.

Current real HTTPS recovery evidence

The coordinating task reran the updated executor against the real TLS collector. verification/continuation-duty-restart-run/ has nine passing checks. After a collector committed a retrieval report and its acknowledgement was deliberately lost, the executor was closed and reconstructed against its durable journal in the same process. It retried the exact report, verified the original signed intake and retained the reported outcome. A new protected delivery was obtained before new storage and copying. Four report intakes were verified across five attempts; both managed stored copies were deleted at controlled expiry. Actual abrupt process exits remain separately covered by the 28-test unit/adversarial suite. This is not an abrupt-process-restart-over-TLS or 600-second endurance claim.

Odexa / Protocol explorer

This page. Your terms.

Inspect this website’s published policy and see how a proposed use is evaluated.

Current pagehttps://odexa.io/guides/duties/
Loading policy…

Published JSON
Open JSON

This is a local policy check, not a signed agreement or proof of agent compliance. Other published licences and applicable rights still apply. How policy evaluation works →

Odexa / Get in touch

Start a conversation.

Tell us what you have in mind. We’ll respond where we can.

We use these details to review and respond to your enquiry. Please leave out confidential information. Submitting does not subscribe you to marketing. Privacy policy.