Upstream Parity Ledger
What this document is
This document records every deliberate divergence between our kernel and the upstream model. The paper states the reference model. Our kernel sometimes chooses a different behavior on purpose. This file is the audit ledger for those decisions.
- Date: 2026-08-24
- Scope:
crates/cordisversus the model in the paper - Method: every divergence lists the claim, the rationale, and the enforcement or test point
Divergence table
| # | Divergence | Decision |
|---|---|---|
| 1 | Failed registrations stay visible | Failed{error} is a terminal rest state with reflective wiring |
| 2 | Peer-dependency compatibility | Majors-only version buckets, no structural checks |
| 3 | Late inject declarations | Eager reconciliation on Active fibers |
| 4 | Hot swap mechanics | Out-of-band trial then promote, honest swap_mode reporting |
| 5 | Dynamic library loading | Strictly opt-in behind hmr, exact fingerprint handshake |
| 6 | Factory collection | Inventory primary, manual chains as fallback |
| 7 | Serial dispatch | Direct alias of Bail, waterfall uses real next continuations |
| 8 | Worker supervision | Reserved exit codes plus stdin-EOF death detection |
| 9 | Log routing | One exporter router fans records to every gated sink |
| 10 | Dependency withdrawal | Genuine loss rests working fibers Pending (reversible); apply errors stay terminal Failed |
| 11 | Dispatch participation knobs | EventOptions{prepend,global} + emit_filtered; filters never exclude global listeners |
| 12 | Reads during transitions | Strict get refuses transitioning owners; get_relaxed is the explicit opt-in |
| 14 | Kernel operations are interceptable | Five meta-events veto or rewrite kernel ops; unregistered path stays zero-cost; sync bridges fall open |
| 15 | Readiness gates wait quietly | Closed ready_when barriers rest fibers Pending (never Failed); availability predicates remain the loud path |
| 16 | Config cascades batch | Concurrent provider updates collapse to one dependent convergence wave |
| 17 | Validation errors carry paths | Pre-flight failures surface message + path issues beside the legacy string |
| 18 | Logger adopted natively | Ring buffer, effect-owned exporters, per-name routing live in the kernel crate |
| 19 | Timers adopted natively | Six fiber-scoped primitives share one std-only wheel thread |
| 20 | Accessor traffic bypasses interception | Name-keyed computed properties resolve outside the internal/get / internal/set waterfalls entirely |
| 21 | Intercept layers are ordered and inspectable | Append-on-set keeps the innermost layer effective; intercept_chain returns outermost..innermost |
| 22 | Restart errors keep the old application | Fiber::update propagates errors with the fiber still Active; a veto parks vetoed_config and returns Ok |
| 23 | Config interception covers activation | The internal/config waterfall consults on first activation too, not only re-applies |
| 24 | Module changes fan out through one graph | change_many computes the affected set read-only first, reloads each plugin once per transaction, and rollback keeps siblings Active (EXCEEDS upstream: no module-graph concept) |
| 25 | Entries relocate without losing identity | PATCH move-then-update answers 409 on conflict; /move renames the {id}:* subtree; in-place refresh preserves the fiber (EXCEEDS upstream: flat key list only) |
| 26 | Subtask cancellation is wired end to end | Sticky cancel tokens honored at step boundaries plus an external trigger (EXCEEDS upstream: reference defines the hook but never wires it) |
| 27 | Deterministic micro calls are cached | LRU+TTL keyed (model, system, input) with cache_hit telemetry; salvage/retry results never cached (EXCEEDS upstream: roadmap prose only) |
| 28 | Guided grammars ride typed hints | Schema-shaped values become json_schema everywhere; raw GBNF stays a provider extension; absent hint = byte-identical wire |
| 29 | Duplicate embeddings cost one backend call | Content-hash dedup on local and HTTP paths fans vectors back to duplicate slots (EXCEEDS upstream: roadmap prose only) |
Each row expands below with the claim, the rationale, and the evidence.
1. Failed registrations stay visible
- Upstream expectation: a factory error leaves the fiber permanently
Inactiveand unreachable. - Claim:
Failed{error}is a terminal VISIBLE rest state. - Detail:
RegistryService::registerreturnsErr. - Detail: the fiber enters the bookkeeping graph through
RegistryService::wire_failed_registration. - Detail:
ReflectServicewiring registers the fiber against the attempted provider key. - Detail: notify fans out, so dependents observe the provider loss reactively and rest
Inactive. - Detail: a later successful registration allocates a fresh fiber id and supersedes the failed fiber.
- Rationale: operators inspect failures directly.
- Rationale: dependents get a real notification instead of silence.
- Rationale: fresh-id supersession keeps the provided slot free for retry.
- Source:
crates/cordis/src/registry.rs,wire_failed_registration - Test: metatheory property 3 legs D-H,
metatheory_dependent_never_active_without_provider
2. Peer dependencies use majors-only buckets
- Upstream expectation: compatibility needs full structural interface checks.
- Claim: compatibility compares majors only.
- Detail: versions are plain
u64values. - Detail:
major(v) = v / VERSION_MAJOR_SCALEandfloor(v) = v % VERSION_MAJOR_SCALE. - Detail:
VERSION_MAJOR_SCALEequals100_000. - Detail: a requirement binds when the major matches AND the provider reaches the floor.
- Detail: any mismatch leaves the dependent fiber
Inactive. - Detail: structural interface compatibility is deliberately NOT attempted.
- Rationale: majors-only buckets cover practical drift between builds.
- Rationale: full structural compatibility remains the open problem the paper defers.
- Source:
Context::provide_versionedandVERSION_MAJOR_SCALEincrates/cordis/src/context.rs - Source:
Fiber::declare_inject_versionedincrates/cordis/src/fiber.rs - Tests: the
version_conformancemodule incrates/cordis/src/metatheory.rs
3. Late inject declarations reconcile eagerly
- Upstream expectation: a late declaration waits for an external refresh trigger.
- Claim: a declaration landing on a fiber resting
Activereconciles eagerly. - Detail:
Fiber::reconcile_after_declareruns with the same transition shape asrefresh. - Detail: satisfied declarations update the epoch in place.
- Detail: unsatisfied declarations undo effects and rest the fiber
Inactive. - Detail: a declaration that races an in-flight refresh folds into that refresh through a pending flag.
- Detail: declarations on
InactiveandFailedfibers wait for the next transition. - Rationale: eager recompute loses no racing declaration.
- Rationale: the quiescence invariant survives every declaration path.
- Source:
Fiber::declare_injectandFiber::reconcile_after_declareincrates/cordis/src/fiber.rs - Source: register paths in
crates/cordis/src/registry.rs - Test: reactive invariant leg of
dependent_never_active_without_provider
4. Hot swap drains then shifts
- Upstream expectation: swap mutates providers in place.
- Claim: swap builds out-of-band, then promotes.
- Detail: new instances build inside a scratch context.
- Detail:
SwapPromotionbridges the new values through intercept bindings. - Detail: the old fiber disposes while the bridge keeps serving consumers.
- Detail: promotion moves bridge values into the store before intercept removal.
- Detail: consumers never observe an absence window.
- Detail: an unverifiable swap reports
swap_mode = "unverified"instead of a fake success state. - Rationale: drain-and-shift proves a zero absence window under concurrency.
- Rationale: honest reporting lets operators tell verified swaps from unverified ones.
- Source:
Loader::replace_providerandSwapPromotionincrates/cordis/src/loader.rs - Tests:
replace_provider_zero_absence_window - Tests:
rebuild_same_type_verified_swapprobes resolution from a concurrent task during the swap
5. Dylib loading is strictly opt-in with a fingerprint handshake
- Upstream expectation: dynamic library loading runs as a first-class default.
- Claim: dylib loading requires the
hmrcargo feature. - Detail: the default production path is file-watch plus
Fiber::reloadthroughwatcher::watch_many. - Detail: as of this change, every dylib load performs an exact ABI fingerprint handshake.
- Detail: the plugin must export
cordis_plugin_fingerprint. - Detail: the returned string must equal the host fingerprint exactly.
- Detail: a missing symbol refuses the load.
- Detail: a mismatched string refuses the load and names both fingerprints.
- Rationale: stale libraries fail fast at load time.
- Rationale: unchecked dylibs corrupt the process across the FFI boundary.
- Source:
load_plugin_soandFINGERPRINT_SYMBOLincrates/cordis/src/hmr.rs - Tests:
load_plugin_so_rejects_missing_fingerprint - Tests:
load_plugin_so_rejects_mismatched_fingerprint
6. Inventory collection is the primary registration path
- Upstream expectation: registration walks an explicit hand-written factory list.
- Claim: inventory collection gathers factories automatically as the primary path.
- Detail: hand-written
register_pluginschains remain as the fallback without theinventoryfeature. - Detail: the linker drops inventory nodes from crates that nothing references.
- Detail: parity tests force-link every contributing crate before collection.
- Rationale: collection deletes a hand-maintained list and its drift bugs.
- Rationale: the linker failure is silent, so it needs a written warning.
- Source:
register_inventory_factoriesincrates/cordis/src/lib.rs - Test:
inventory_registry_matches_expected_factory_setintests/inventory_parity.rs
7. Serial dispatch aliases Bail, waterfall composes handlers
- Upstream expectation: serial dispatch differs from bail semantics.
- Claim:
Dispatch::Serialis a direct alias ofDispatch::Bail. - Detail: both variants run the same
run_bail_handlerscode path. - Detail: waterfall is around-middleware.
- Detail: every waterfall handler receives a real
nextcontinuation. - Detail: the terminal
nextruns the core operation. - Detail: no sentinel value ever stops a chain.
- Rationale: one shared bail mode removes a near-duplicate implementation.
- Rationale: around-middleware composition matches the paper shape directly.
- Source:
EventsService::dispatchincrates/cordis/src/events.rs - Tests:
serial_stops_at_first_non_null_result - Tests:
waterfall_around_short_circuit_skips_core
8. Worker supervision uses reserved exit codes plus stdin EOF
- Upstream expectation: the paper defines no process supervision model.
- Claim: supervised workers terminate through a fixed exit-code protocol.
- Detail:
EXIT_RESTART(51) asks the daemon for a fresh worker. - Detail:
EXIT_QUIT(52) stops without a restart. - Detail:
EXIT_BOOT(53) surfaces boot failure non-zero to the manager. - Detail: codes sit in the 51-53 band, clear of shell (1-2) and panic (101) codes.
- Detail: workers set
CORDIS_SUPERVISEDwatch stdin; EOF means the daemon died. - Rationale: pipe EOF is the only loss-free signal that survives daemon SIGKILL.
- Source:
crates/cordis/src/worker.rs,src/supervisor.rs - Tests:
exit_codes_are_distinct - Tests:
child_exit_codes_drive_loop
9. Log routing fans out through one exporter router
- Upstream expectation: the paper defines no observability surface.
- Claim: one router fans call records out to every registered exporter.
- Detail: per-exporter level gates filter records before delivery.
- Detail: exporter failures stay contained; inference never fails on them.
- Detail: registration validates once; duplicate registrations are skipped.
- Rationale: a single fan-out point replaces ad hoc sink plumbing per consumer.
- Source:
ExporterRouterincrates/ares-llm/src/exporter.rs - Tests:
router_fans_out_to_all_exporters - Tests:
accepts_gate_filters_records
10. Dependency withdrawal is reversible for working fibers
- Upstream expectation: a fiber whose provider disappears rests
Inactive(or is disposed) and never comes back on its own. - Claim: a previously-working runner fiber whose dependency genuinely vanished disposes its effects LIFO under
Unloadingand rests a newPendingstate; when the provider returns it reactivates throughLoading. - Detail:
Pendingis reserved for reactive waiting only — an apply error still rests terminalFailed{error}(row 1), and a peer-version constraint refusal over an existing-but-incompatible provider still restsInactivebecause the provider remains available. - Detail: eligibility requires one fully-satisfied refresh pass first; registration cannot mark a fiber eligible.
- Detail:
Pendingfibers reserve their registry key and surviveprune_disposed, so reactivation needs no re-registration. - Rationale: the paper's permanently-Inactive outcome discards a healthy instance that only waits for its dependency; keeping it reversible preserves work.
- Source:
FiberState::Pending, the reactive-loss branch ofFiber::refreshincrates/cordis/src/fiber.rs - Tests:
dependent_reactivates_when_provider_returns,failed_stays_failed_on_dep_return,pending_fiber_survives_prune_disposed
11. Dispatch participation knobs and filtered emits
- Upstream expectation: listener registration has fixed semantics with no ordering or participation control.
- Claim: flat listeners register through
on_with/once_withwithEventOptions { prepend, global };emit_filteredruns a per-dispatch predicate over non-global listeners. - Detail:
prepend: trueinserts at the front of the dispatch-order list;global: truemarks the listener realm-agnostic, and filters never exclude it. - Detail: a filter exclusion skips one dispatch without unregistering the listener.
- Detail: the historical
on/once/emitsignatures delegate unchanged, and the broadcast bus fan-out is not filtered. - Rationale: per-realm policies need ordered, selectively-participating listeners without duplicating the bus.
- Source:
EventOptions,EventsService::on_with/once_with/emit_filteredincrates/cordis/src/events.rs - Tests:
prepend_ordering_observed,filter_excludes_nonmatching_contexts,global_bypasses_filter
12. Reads during transitions are explicit and relaxed
- Upstream expectation: every read either resolves an Active value or fails; mid-transition values are unreachable by construction.
- Claim: strict
Context::getkeeps refusing providers resting in transitional states;Context::get_relaxedserves locally-owned values while their owner sits inLoading/Reloading/Unloading/ reactivePending. - Detail: terminal rest states stay refused even relaxed — disposed owners (undos already ran) and
Failed{error}owners return nothing. - Rationale: lifecycle and observer code must inspect the value that is about to serve or was just retracted; making that a distinct method keeps the default read conservative.
- Source:
Context::get_relaxedincrates/cordis/src/context.rs - Test:
relaxed_read_succeeds_while_provider_transitioning
13. Fiber state observers
- Upstream expectation: the model defines no notification surface for individual fiber state changes.
- Claim:
Fiber::subscribe_statefans every lifecycle transition out to synchronous observers. - Detail: observers run inline under the short state-lock critical section and MUST NOT call back into the fiber.
- Detail: observer panics are caught, so one broken observer cannot corrupt a transition; cancelled subscriptions are pruned on the next event.
- Rationale: tooling (admin surfaces, tests, supervision) needs transitions as they happen, not just polling after quiescence.
14. Kernel operations are interceptable through meta-events
- Upstream expectation: reads, writes, config resolution, restart schedules, and listener registration are fixed kernel behavior with no override points.
- Claim: five veto meta-events (
internal/get,internal/set,internal/config,internal/update,internal/listener) wrap those operations and aninternal/dispatchobserver reports every non-internal dispatch with(mode, name, args); the un-intercepted path is a zero-cost gate, and synchronous bridges FALL OPEN on runtimes that cannot park the worker. - Detail:
internal/get— a non-null terminal replaces the value a strict read returns,{"refuse": true}fails the lookup outright, null passes, a chain error refuses the read; a redirect verdict continues the lookup at the parent frame. - Detail:
internal/set— a chain error vetoes THIS write; the previous binding stays fully intact (no store/owners/version mutation). - Detail:
internal/config— the chain's non-null terminal IS the effective config staged for that apply pass; a chain error rests the fiber terminalFailed{error}(row 1 semantics unchanged). - Detail:
internal/update— a bail or explicit JSON false skips the restart; the fiber keeps serving its current application and the deferred config stays visible viavetoed_config. - Detail:
internal/listener— a bail or chain error cancels the registration and the caller receives an INERT handle; neither registry ever sees the listener (fail-closed). - Detail: every consult checks
listener_count == 0first (map-lookup cost); a thread-local fence keeps operations made inside a chain un-intercepted; single-thread tokio flavors log a warning and fall open, matching historical behavior. - Detail:
bail_from/waterfall_from/waterfall_async_fromcarry the operating context through an optional per-dispatchListenerFilter; exclusions skip one dispatch without unregistering. - Rationale: policy layers need to observe and veto kernel operations without duplicating them; the zero-cost gate keeps the default path byte-identical for every existing caller.
- Source:
INTERNAL_*_EVENTconstants,intercept_get/set/config/update/listener,bail_from/waterfall_from/waterfall_async_from, and the synchronous bridges incrates/cordis/src/events.rs - Source: consult points in
Context::get/ the provider-write path (crates/cordis/src/context.rs); config staging and the update veto incrates/cordis/src/fiber.rs - Tests:
get_interceptor_rewrites_read,set_interceptor_vetoes_write_leaves_old_value,config_interceptor_rewrites_effective_config,update_interceptor_veto_skips_restart_keeps_config,listener_interceptor_bail_cancels_registration_inert_handle,internal_dispatch_observes_non_internal_only,interceptor_error_fails_fiber_activation,target_carrying_dispatches_filter_per_dispatch
15. Readiness gates wait quietly; availability predicates fail loudly
- Upstream expectation: the model defines no way to hold a produced service out of rotation while its environment warms up (and nothing distinguishes that from failure).
- Claim:
register_with_readinessinstalls a composableReadinessBarrierconsulted before every activation pass; while it reports not-ready the fiber rests inspectablePending— quiet waiting that NEVER becomesFailed— while availability predicates (Service::check) remain the loud complement restingFailed{error: "availability predicate rejected service"}. - Detail:
ReadinessBarrier::new(pred)wraps oneFn(&Arc<Context>) -> bool;.and(other)AND-composes;with_readiness([a, b, c])folds any number of barriers (an empty list is vacuously ready). - Detail:
.watching([TypeId])unions the provider keys whose settlements re-kick the gated fiber through theReflectServicefan-out — an external provide or withdrawal re-evaluates the gate without touching the fiber. - Detail: the factory runs once at registration (config errors still surface immediately); a closed gate only keeps the produced service OUT of consumer reach because strict
getrefuses non-Activeowners; opening the gate activates without re-running the factory. - Rationale: not-ready-yet (warming caches, absent external system) differs fundamentally from broken; conflating them buries healthy waiting fibers under failure noise, and separating them lets operators read intent from state alone.
- Source:
ReadinessBarrier,with_readiness,register_with_readiness, and the re-kick wiring incrates/cordis/src/registry.rs - Source: the readiness consult in
Fiber::refresh(crates/cordis/src/fiber.rs) - Tests:
ready_when_holds_pending_until_true_then_activates,readiness_composes_and_semantics,external_rekick_reactivates_waiting_fiber
16. Concurrent config updates collapse to one cascade wave
- Upstream expectation: every provider settle triggers its own full dependent refresh wave.
- Claim: an in-flight ledger marks providers mid-reapply; dependents defer during the window and converge EXACTLY ONCE per settled batch.
- Detail:
CASCADE_INFLIGHTmaps fiber id to open-window count (reentrant-safe);Loader::drive_fiber_updateopens and closes windows around one live re-apply. - Detail: the kernel refresh path consults
cascade_any_inflight, so a storm of racing patches costs one dependent apply pass and ends Active with the final config. - Rationale: N concurrent patches against one provider must not cost N dependent convergence waves.
- Source:
CASCADE_INFLIGHT,cascade_begin/cascade_end/cascade_any_inflightincrates/cordis/src/loader.rs - Test:
concurrent_config_updates_collapse_to_single_cascade
17. Config pre-flight failures carry structured issues
- Upstream expectation: configuration errors are lossy prose strings.
- Claim: plugins reject configs with
ValidationIssue { message, path }items aggregated in aValidationError;CordisError::validationlifts the aggregate into the existinginvalid config:class, and the loader trial stashes per-entry failures so the admin PATCH answers 4xx with a machine-readableissuesarray beside the legacyerrorstring. - Detail: stash slots mirror the LATEST trial outcome; recording a non-validation error clears the entry and consumption removes it, so a later successful patch carries no
issues. - Rationale: API consumers need to render field-level feedback, not parse sentences.
- Source:
ValidationIssue/ValidationError/ trial stash incrates/cordis/src/error.rs;CordisError::validationincrates/cordis/src/service.rs; issue attachment incrates/ares-http/src/api/handlers/admin/cordis.rs - Test:
patch_endpoint_returns_structured_issues_on_bad_config
18. The logger lives in the kernel crate
- Upstream expectation: logging ships as a satellite console package beside the kernel.
- Claim: the logger is adopted NATIVELY (
cordis::logger) with upstream-style semantics: bounded ring, effect-owned exporter sinks, per-name level routing, printf rendering. - Detail:
LoggerServicekeeps the last 1000Messages (monotonic sequence, timestamp, name, kind, numeric level, args, fiber label) and snapshots without copying payloads. - Detail: exporters are effect-owned —
registerreturns aDisposablewhose disposal removes the sink;ExporterConfiggates per name and truncates rendered text (default cap 4096 chars, char-boundary safe). - Detail: thresholds resolve per-name pin, then the
LoggerInterceptoverride (read through the relaxed channel, so per-fiber overrides apply on child contexts), then the default level (Debug);enabledbails BEFORE argument assembly. - Detail: rendering supports
%s %d %i %f %o %O %c %C %%; unknown specifiers and exhausted arguments stay literal;%cpicks a stable ANSI16 slot by FNV-1a hash of the logger name,%Cadds bold;hyphenate/derived_nameyield kebab-case logger names. - Detail: the
Contextfacade (ctx.log/info/warn/debug/error/log_with) is a no-op when no logger is provided. - Rationale: observability belongs where fibers dispose, so sink lifetimes tie to effects instead of a satellite package boundary; the multi-package layering ceremony is deliberately not replicated.
- Source:
LoggerService,Exporter,ExporterConfig,LoggerIntercept,Message::render,hyphenateincrates/cordis/src/logger.rs - Tests:
buffer_bounded_at_capacity_snapshot_reads,level_routing_per_name_with_default_fallback,printf_placeholders_format_correctly,logger_intercept_overrides_level,hyphenate_and_derived_names,exporter_disposal_removes_sink
19. Timer primitives are fiber-scoped and std-only
- Upstream expectation: timing ships as a dedicated satellite package with its own runtime assumptions.
- Claim: six primitives (
timeout,sleep,interval,interval_stream,debounce,throttle) live natively incordis::timer, run on ONE shared wheel thread, and attach to the owning fiber through labeled undos. - Detail: the wheel is a min-heap on a dedicated
cordis-timerthread; due entries drain under one short critical section and callbacks run outside the lock; panics are caught and the thread survives. - Detail: registrations made under
with_current_fiberpushtimer:-labeled undos, soFiber::dispose(or a reactive unload) cancels them; dropping a handle does NOT cancel; out-of-scope registrations degrade to warned orphan handles that stay explicitly disposable. - Detail: a disposed
Intervalstream yields exactly ONE finalErr(InactiveEffect)then closes; queued live ticks are discarded so teardown is the final observation. - Detail:
debouncecollapses a burst into one trailing delivery after the last call;throttledelivers leading-edge plus optional trailing in a fixed window. - Rationale: timers must die with the fiber that owns them or they leak firings past teardown; a shared thread keeps thousands of registrations at one thread's cost with no async runtime dependency.
- Source:
timeout/sleep/interval/interval_stream/debounce/throttle,with_current_fiber,Scheduled,Intervalincrates/cordis/src/timer.rs - Tests:
timeout_fires_once_and_disposes_with_fiber,timeout_dispose_before_deadline_prevents_fire,interval_ticks_repeatedly_and_stops_on_dispose,interval_stream_final_err_on_dispose,debounce_collapses_bursts,throttle_trailing_edge_respected
20. Accessor traffic bypasses interception
- Upstream expectation: every value read or write consults the
internal/get/internal/setveto waterfalls. - Claim: name-keyed computed properties (
register_accessor) resolve OUTSIDE both waterfalls — resolving an accessor never consults or re-enters a veto chain. - Detail:
Accessor::{read_only, read_write, setter_only}installs a getter/setter pair beside the TypeId service store; registration returns anEffectHandlewhose disposal removes the declaration and every alias. - Detail:
Context::aliasbinds an alternate name through the SAME registration; duplicate declarations (including alias collisions) are rejected withDuplicateProvider. - Detail: typed reads surface
CordisError::PropertyTypeMismatchinstead of a silentNone; writes to a read-only property are refused withCordisError::ReadOnlyProperty. - Rationale: computed properties are policy plumbing, not provider state — vetoing them would let an interceptor break accessor invariants it cannot see.
- Source:
Context::register_accessor,Accessor,Context::alias,EffectHandleincrates/cordis/src/context.rs - Tests:
accessor_read_write_roundtrip,duplicate_accessor_declaration_rejected,readonly_property_rejects_set,dispose_accessor_resolves_none,alias_resolves_same_value,accessor_bypasses_intercept_waterfalls
21. Intercept layers are ordered, append-on-set, and inspectable
- Upstream expectation: one intercept binding per key; later registrations replace earlier ones (last-write-wins).
- Claim: intercept layers per TypeId form an ordered outermost..innermost sequence; NEW registrations APPEND, so the innermost layer stays effective for all existing getters.
- Detail: append-on-set means no existing caller observes a behavior change when another layer joins.
- Detail:
Context::intercept_chain(tid)returns every layer outermost..innermost for inspection and restart-decision logic. - Detail:
Context::chains_structurally_equalcompares two chains by shared-instance identity (Arc::ptr_eq) per layer pair; erased values carry no comparable contract, so freshly-built values compare unequal by design. - Rationale: layered policies need composition without clobbering, and restart decisions need an honest equality test over opaque layers.
- Source:
Context::intercept_chain,Context::chains_structurally_equal, layer storage incrates/cordis/src/context.rs - Tests:
chained_layers_append_innermost_effective,intercept_chain_returns_all_layers_in_order
22. Restart errors keep the old application; vetoes defer loudly
- Upstream expectation: an update-pass failure leaves the fiber in an unspecified mid-transition state.
- Claim:
Fiber::updatereturnsResult<(), CordisError>— a restart-path error propagates to the caller and the fiber staysActiveserving its OLD configuration; aninternal/updateveto parks the deferred config inFiber::vetoed_configand returnsOk. - Detail: error propagation never disposes effects of the still-running application.
- Detail: the vetoed config remains inspectable through
vetoed_config()so operators can see what was declined and why. - Rationale: a failed restart must not destroy the working instance, and a silent skip must still be observable.
- Source:
Fiber::update,vetoed_configincrates/cordis/src/fiber.rs - Tests:
update_error_stays_active_old_config,update_veto_defers_config_and_returns_ok
23. Config interception covers the activation path
- Upstream expectation: config rewriting applies only on later re-applies; first activation runs the raw config.
- Claim: the
internal/configwaterfall is consulted on the ACTIVATION path too, so rewrites apply on first activation identically to re-applies. - Detail: the same non-null-terminal-becomes-effective-config semantics hold on both paths (row 14).
- Rationale: activation-time-only rewrites would make a policy's effect depend on whether the fiber happened to start fresh.
- Source: config-waterfall consult in the register/activation path in
crates/cordis/src/registry.rs - Test:
config_waterfall_covers_activation_path
24. Module changes fan out through one dependency graph
- Upstream expectation: no module-level change propagation exists; each watcher event maps to at most one reload target.
- Claim:
ModuleGraphmaps module keys to dependencies;change_manycomputes the TRANSITIVE affected plugin set read-only FIRST, then reloads each affected plugin EXACTLY ONCE per transaction; a failing reload rolls back that plugin while successfully reloaded siblings stayActive. - Detail:
ModuleReloadimplementations perform the reloads;ChangeOutcomeclassifies the transaction result. - Detail: the file watcher's debounced batch fans through a registered
ModuleGraphwhen one is provided on the context; WITHOUT registration the watcher path is unchanged (opt-in). - Rationale: batched filesystem events must not reload shared dependents N times or leave siblings dead because one peer failed.
- Source:
ModuleGraph,ModuleEntry,ModuleReload,ChangeOutcome,change_manyincrates/cordis/src/module_graph.rs; fan-out wiring incrates/cordis/src/watcher.rs - Tests:
dependency_change_reloads_dependents_transitively,batched_changes_reload_each_plugin_once,rollback_keeps_successful_siblings_active,watcher_module_graph_fan_out_reloads_dependents,module_graph_without_registration_is_ignored
25. Entries relocate without losing fiber identity (we exceed upstream)
- Upstream expectation: entries form a flat id-keyed list; relocation means delete-plus-recreate with a fresh fiber.
- Claim: PATCH accepts optional
parent/position(EntryPosition) applied move-THEN-update (invalid placements answer 409 before any mutation),POST /admin/cordis/entries/{id}/moverelocates an entry with its whole{id}:*subtree in one rename cascade, and a valid move preserves fiber identity via in-place refresh. - Detail: moving into a descendant is refused; disabled groups move suppressed-then-restored.
- Detail: invalid moves touch neither the entries file nor the live tree; unknown ids answer 404.
- Rationale: hierarchical entry organization must not cost consumer-visible dispose/recreate windows.
- Source:
EntryPosition,EntryTree::move_entry,subtree_ids,Loader::move_entryincrates/cordis/src/loader.rs;patch/move_cordis_entryhandlers incrates/ares-http/src/api/handlers/admin/cordis.rs - Tests:
move_preserves_fiber_identity_and_lands_update_in_new_parent,descendant_move_refused,subtree_rename_cascades_descendants,disabled_group_move_suppresses_start_then_restores,patch_endpoint_moves_entry,patch_endpoint_invalid_move_conflicts_without_mutating
26. Subtask cancellation is wired end to end (we exceed upstream)
- Upstream expectation: the reference client defines cancellation hooks but never wires them into its delegation loop.
- Claim: delegated subtasks register sticky cancel tokens keyed by run/skill id;
SkillEngine::cancel_subtask()flips a token exactly once and is honored at step boundaries alongside theEmergencyStophook; an aborted subtask integrates nothing into the parent. - Detail: quote-aware delegation argument parsing: double-quoted segments are single tokens (backslash escapes inside quotes);
--parallellatches split-per-token mode with|separators ignored,--modelconsumes exactly one token,--toolsenables the inner tool loop; precedence is flags > profile > global. - Rationale: long-running delegated work needs an external off switch that lands between model rounds, not only at process exit.
- Source:
SubtaskCancelToken,SkillEngine::cancel_subtask,registered_cancel_token, step-boundary checks incrates/ares-agent/src/skills/engine.rs;parse_flagstokenizer incrates/ares-agent/src/skills/mod.rs - Tests:
cancel_token_aborts_subtask_between_rounds,parse_flags_quote_aware_tokens
27. Deterministic micro calls are cached; repaired answers are not (we exceed upstream)
- Upstream expectation: the reference roadmap describes response caching but ships none; every identical micro call re-hits the network.
- Claim: deterministic-class micro outcomes serve from a bounded LRU map keyed by a content hash over
(model, system template, input); answers reached through retries or salvage fallback are NEVER cached. - Detail: default 256 entries, 15-minute TTL, master switch via
MicroCacheConfig. - Detail: hits skip the network entirely, report
latency_ms: 0, and carry thecache_hittelemetry flag. - Rationale: classify/tag-style enrichment calls dominate micro traffic and their answers are stable; a repeated or repaired request proves the call was NOT deterministic-class, so caching it would pin a bad answer.
- Source:
MicroCacheConfig,MicroOutcome::cache_hit,cache_key,LruOutcomeCacheincrates/ares-llm/src/micro.rs - Tests:
identical_inputs_serve_cached_outcome,retries_exhausted_falls_back_to_salvage(salvage path stays uncached by construction)
28. Guided grammars ride typed hints with byte-identical absence
- Upstream expectation: constrained output requires per-provider request surgery with no portable hint channel.
- Claim:
GenerationHints::guided_grammarcarries a schema-shaped JSON value asresponse_formatjson_schemaon every OpenAI-compatible path; raw GBNF/EBNF text rides the provider-specificguided_grammarextension field on NON-streaming OpenAI-compatible requests; providers without a channel silently ignore the hint; an ABSENT hint leaves the wire byte-identical. - Detail: classification is structural — a JSON object with an object root is a schema; anything else is raw grammar text.
- Rationale: one opt-in hint field covers structured outputs where supported and vendor grammar extensions where they are not, without changing default requests.
- Source:
GenerationHints::guided_grammarincrates/ares-llm/src/client.rs; classification andGUIDED_GRAMMAR_EXTENSIONincrates/ares-llm/src/openai.rs - Test:
grammar_hint_present_reaches_request_builder
29. Duplicate embeddings cost exactly one backend call (we exceed upstream)
- Upstream expectation: the reference roadmap mentions embedding dedup but implements none; every input in a batch hits the backend.
- Claim: per-request content-hash dedup collapses duplicate inputs (whitespace-normalized SHA-256) BEFORE the backend call on BOTH local and HTTP embedding paths; computed vectors fan back to every duplicate slot.
- Detail:
DedupPlanmaps duplicates to the first occurrence's slot; callers receive full-length results. - Rationale: identical texts in one batch are common (templates, retries) and each costs a paid embedding call.
- Source:
DedupPlan,content_hash_hex,normalize_for_dedupincrates/ares-rag/src/embeddings.rs - Tests:
dedup_plan_maps_duplicates_to_first_occurrence_slot,duplicate_texts_single_backend_call_vectors_fanned_back,content_hash_hex_ignores_whitespace_differences_only
Properties we prove beyond the paper
crates/cordis/src/metatheory.rs proves five properties as executable checks.
These hold regardless of the divergence choices above.
- Quiescence after every operation (
quiescence_after_every_op). Every fiber rests in a well-defined state between operations. Transitional states appear only mid-await, never at rest. Allowed rest states include the reversiblePending(row 10) and terminalFailed{error}(row 1); onlyActivefibers must hold all declared injects available. - Registration confluence (
order_confluence_of_registrations). Registration order does not change the final graph. - Reactive spatial invariant (
dependent_never_active_without_provider). A dependent never activates while its provider is absent. It activates reactively when the provider appears. - LIFO dispose restores the store (
lifo_dispose_restores_store). Disposal unwinds effects in strict LIFO order. The store returns to its pre-registration contents. - Version-conformance flips (
version_conformancemodule). A compatible upgrade flips the dependent back toActive. A mismatch holds it atInactive.
Maintenance note
Any pull request that changes kernel semantics MUST add a row here or update an existing row. State the claim, the rationale, and the enforcement point in the entry. Reviewers reject semantic kernel changes without a ledger entry. Before merge, re-run the cited tests.