Internet-Draft Cedulon Decision Profile September 2026
Dogru Expires 8 March 2027 [Page]
Workgroup:
Network Working Group
Internet-Draft:
draft-dogru-cedulon-decision-profile-00
Published:
Intended Status:
Informational
Expires:
Author:
E. C. Dogru
VERAX TEKNOLOJI LIMITED SIRKETI

Cedulon Decision Profile: Reconciling an Agent's Decisions Against Its Effects

Abstract

The Cedulon core document reconciles an issuer's signed Spend Receipts against an authenticated extract of a payment rail and reports, over a declared population, that no settlement lacks a receipt and no settled receipt is absent from the rail. Money is the special case that document implements. This document defines a second population on the same reconciler. A Decision Record is signed by the party that decided whether an agent may act; an Effect Extract is an authenticated list of the effects that actually occurred on a channel. An allow must be matched by exactly one effect whose content hash the record named; a refusal must be matched by none. The Decision Record claim set, the Effect Extract shape, the points at which the reconciliation departs from the spend rules, the finding codes, and one media type are defined. The text is provisional and the companion implementation carries the profile prepared and unpublished.

Status of This Memo

This Internet-Draft is submitted in full conformance with the provisions of BCP 78 and BCP 79.

Internet-Drafts are working documents of the Internet Engineering Task Force (IETF). Note that other groups may also distribute working documents as Internet-Drafts. The list of current Internet-Drafts is at https://datatracker.ietf.org/drafts/current/.

Internet-Drafts are draft documents valid for a maximum of six months and may be updated, replaced, or obsoleted by other documents at any time. It is inappropriate to use Internet-Drafts as reference material or to cite them other than as "work in progress."

This Internet-Draft will expire on 8 March 2027.

Table of Contents

1. Introduction

The Cedulon core document [CEDULON] answers one question about an agent that spends: did every settlement on the rail have a receipt behind it, and did every settled receipt reach the rail? It answers it by closing three signed objects over a declared population: the issuer's records, an authenticated extract of the counterparty system, and epoch checkpoints that total the records. The verifier holds the keys out of band and the report names the population it covered.

An agent that acts without spending raises the same question with different nouns. A party decided whether the agent may reply, post, send, or call; a channel carried whatever the agent then did. Did every effect on the channel have a decision behind it? Did every allowed action occur, once, with the content that was allowed? Did anything occur that was refused? Section 19 of [CEDULON] reserves later profiles in name only, and its Section 19.3 sketches the same completeness calculus for other consumable resources: compute, data, energy. This document is a different population on the same reconciler, decisions against effects rather than another unit of spend, and it is the first profile written out.

The profile keeps the core's three roles and its verification algorithm. What changes is the record, the row, the binding between them, and the words the report uses. What does not change is measured: the companion implementation holds the spend behaviour byte for byte behind a golden file, and every rule in this document that departs from the spend rules is stated as a departure.

This document is a companion to the core document, not a revision of it. It is not an IETF working-group item. Its requirement language is provisional in the sense Section 19 of [CEDULON] gives the structures it reserves: a direction written with the core's discipline, not a commitment, and a later revision may change it. The companion implementation carries the profile prepared and unpublished.

2. Terminology

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here.

Terms defined in the core document keep their meaning here: Policy Decision Point, epoch checkpoint, trust root, population, finding, warning, guarantee. The following are specific to this profile.

Decider:

The party that decides, per request, whether the agent may act. It signs Decision Records and epoch checkpoints over them. Its key is the issuer root of this profile (Section 7).

Subject:

The party on whose request the decision was taken, named in the record as an opaque identifier.

Decision Record:

A COSE_Sign1 object signed by the Decider stating one decision: allow, deny, or defer, with the request it answered, the policy it applied, and, for an allow, the reference and the content hash of the effect it allowed (Section 4).

Effect:

One thing that happened on a channel as a result of, or in the absence of, a decision: a message sent, a post made, a call placed. It is identified by a reference, classed by a short name, and bound by the SHA-256 of its content.

Channel:

The system on which effects occur and from which an Effect Extract is taken. It plays the role a rail plays in the core document.

Effect Extract:

The authenticated list of effects on one channel, for one Decider, over one window (Section 5). It plays the role a rail extract plays in the core document.

Refusal:

A Decision Record whose decision is deny or defer. A refusal expects no effect.

3. The population

The core document's reconciler closes an issuer record against a counterparty row over a declared population. This profile fills the same three roles:

Table 1
Role Spend (core) Decision (this document)
Issuer record Spend Receipt Decision Record
Counterparty row settlement record on a rail extract effect row on an Effect Extract
Match key ref ref
Content binding amount and currency equal allow: a row exists and effectHash is equal; refusal: no row
Record that expects no row outcome aborted decision deny or defer
Aggregate witness checkpoint totals per currency checkpoint totals per decision kind
Declared population account, rail, window decider, channel, window

Which population a presented document belongs to is the verifier's call, made by the profile it applies, and never the document's. A verifier applying this profile MUST read every presented record as a Decision Record and every presented extract as an Effect Extract, and MUST refuse by name a document that does not have that shape; it MUST NOT infer the population from members a body happens to carry (MUST-DP-1). The companion found the alternative wrong in both directions: a rail extract that added a member named effects was re-routed away from the spend rules it was subject to, and an Effect Extract handed to the spend rules crashed before any report existed. Under this profile a rail extract is the wrong document and is refused as one; under the spend rules an Effect Extract is refused the same way.

4. Decision Record

A Decision Record is COSE_Sign1 with the header profile of Section 6.2 of [CEDULON]: deterministic CBOR, alg -19 (Ed25519, [RFC9864]), kid mandatory and computed as the core states, an empty unprotected header refused by name if not empty, and the payload the CBOR encoding of the claim map below. The content type header parameter is application/cedulon-decision-record+cbor (Section 10).

4.1. Claim labels

The labels lie in the Private Use range of the CWT Claims registry [RFC8392], below the block the core document uses for the Decision Token (-70301 to -70305) and the countersignature (-70401, -70402), so that no two Cedulon claim maps share a label. Every claim annotated hash carries a SHA-256 [RFC6234] digest rendered as exactly 64 lowercase hexadecimal characters, the grammar of Section 6.1 of [CEDULON], and a value outside that grammar is refused by name at signing and at verification.

Table 2
Label Claim CBOR type
-70501 decider tstr
-70502 subject tstr
-70503 requestHash tstr (hash)
-70504 policyHash tstr (hash)
-70505 inputsHash tstr (hash) / null
-70506 decision tstr (allow / deny / defer)
-70507 reasonCode tstr
-70508 ref tstr / null
-70509 effectHash tstr (hash) / null
-70510 timestampMs uint
-70511 nonce tstr
-70512 prevRecordHash tstr (hash) / null

All twelve labels are always present; a nullable claim carries CBOR null when it has no value.

decider and subject are opaque identifiers chosen by the deployment. requestHash is the SHA-256 of the request the Decider evaluated, in the canonical encoding of Section 7 of [CEDULON] when the request is a JSON document and over its UTF-8 octets when it is text; this document does not fix the request's fields, and a deployment MUST state what it hashes. policyHash is the SHA-256 of the canonical policy document the Decider applied. inputsHash, when not null, is the SHA-256 of whatever further context the Decider consulted, encoded the same way, so that a later reader can tell two decisions on the same request apart by what else was on the table. reasonCode is a short token the deployment defines; it is carried, not interpreted.

ref is the reference under which the allowed effect will appear on the channel, and the key on which the reconciliation matches. effectHash is the SHA-256 of the content of the effect the Decider allowed, over the octets the channel will carry: for a text reply, the UTF-8 octets of the text. The Effect Extract computes the same digest over the same octets (Section 5), so equality of the two is equality of content.

timestampMs is the decision time in POSIX milliseconds. nonce identifies the record. prevRecordHash links records into the Decider's chain: it is the SHA-256 of the previous record's COSE_Sign1 octets, the same input the core's receiptHash takes on the COSE path (Section 7.1 of [CEDULON]), or null for the first record of a chain.

4.2. Claim rules

A signer MUST refuse to sign, and a verifier MUST reject, a claim set that breaks any of the following, naming the rule in the refusal (MUST-DP-2):

  • decision is one of allow, deny, defer.

  • Every hash-annotated claim that is not null matches the hash grammar.

  • timestampMs is a non-negative integer of magnitude at most 2^53 - 1, the uint the label table states; a CBOR decoder hands back any number, and the rule is what makes the table true.

  • An allow carries a non-empty ref and a non-null effectHash. An allow that names no effect is a decision the reconciliation cannot close, and an allow that names no reference is one it cannot find.

  • A refusal carries effectHash null. A refusal binds to the absence of an effect, never to a content hash, so a hash on a refusal would be a claim the audit cannot measure and a second reading of whether the effect occurred. A refusal MAY carry a ref: it names what was refused, and an effect appearing under that reference is the worst finding this profile has (Section 6.3).

The verifier MUST apply these rules itself, on the claim map it decoded from the signed payload, and MUST NOT rely on the signer having applied them (MUST-DP-3). The Decider is the party under audit. A Decider that signed a well-formed COSE_Sign1 over a claim map that skips a rule has produced an object whose signature verifies, and a verifier that checked only the signature and the equality of the decoded map with the presented claims would attest it. The companion implementation did exactly that until it was measured: an allow with no reference, signed below the signer's own rules under the pinned decider key, verified true, was attested, was counted as unmatched, and the audit still said the books balanced. The rules now run at both ends.

4.3. Presentation and confusion

A Decision Record is presented as Section 6.3 of [CEDULON] states for the core's COSE objects: the signed octets, the decoded claim set, and the Decider's public key as a SubjectPublicKeyInfo PEM beside them. The carried key is not an identity source. Under a pinned decider key a record that verifies under the pin while carrying another key is reported as carried-key-mismatch, a warning, and stays attested; with no pin held the signature check that runs against the carried key says the record is internally consistent and nothing about who signed it.

A Decision Record is not a Decision Token. The core's Decision Token (Section 8 of [CEDULON]) is the portable encoding of a PDP allow, carried by the party that will spend; a Decision Record is the Decider's own log of what it decided, kept for audit, and it exists for refusals as well. The two carry different content types and different claim maps. A verifier MUST reject a Decision Record whose content type is not application/cedulon-decision-record+cbor, and MUST reject a token presented as a record or a record presented as a token, on the content type, before the signature is checked and before any claim is read (MUST-DP-4).

4.4. The Decider's chain and checkpoints

Decision Records chain on prevRecordHash the way Spend Receipts chain on prevReceiptHash, and the Decider signs epoch checkpoints over them with the checkpoint claim set of Section 11.1 of [CEDULON] unchanged: receiptCount is the number of records in the window, chainHeadHash is the SHA-256 of the last record's COSE_Sign1 octets, and totals is a map from the three decision kinds to decimal counts, {"allow": n, "deny": n, "defer": n}, each rendered as a text string as the core renders its currency totals. A verifier compares the totals it computes over the attested records in the window against the signed map, and a difference is checkpoint-total-mismatch as in the core.

Two records that claim the same position in a chain cannot both link to it: the second record's prevRecordHash must be the first's hash, so a Decider that signs two decisions under one nonce, or presents one record twice, breaks its own chain and the walk names the break. The chain is the equivocation control of this profile, and a verifier MUST walk it over every presented record that carries the pinned decider key, not only over the records that verified, so that a record that claims the pin and fails the rules is named by the walk rather than dropped from the population without a word (MUST-DP-5).

5. Effect Extract Profile

A verifier checks completeness against an Effect Extract, not against the Decider's own records alone. The extract is the channel's account of what happened, obtained independently of the Decider, and the profile is only as strong as that independence (Section 7).

5.1. Body and row schema

The extract body is one JSON document with exactly this shape:

Table 3
Member JSON type
deciderId string (non-empty)
channelId string (non-empty)
windowStartMs number (POSIX milliseconds, a safe integer)
windowEndMs number (POSIX milliseconds, a safe integer, greater than windowStartMs)
effects array of effect rows

Each effect row is a JSON object with exactly these members:

Table 4
Member JSON type
ref string (non-empty; the reference the Decision Record named)
effectHash string (SHA-256 of the effect's content, 64 lowercase hex)
effectClass string (non-empty; a short class name the channel defines, such as a reply or a post)
timestampMs number (POSIX milliseconds, a safe integer, inside the window)
actor string (optional; the party the effect reached)

These member names are normative. The body and its rows follow the core's rail extract (Section 9 of [CEDULON]) in every rule that document states for a JSON body: the text is read for a repeated member name before it is parsed and refused as json-duplicate-key; integers are safe integers; the window is half-open and MUST end after it starts; a missing member, a wrong type, an empty identifier, or a hash outside the grammar is refused by name at both ends, by the signer before it signs and by the verifier before it checks a signature.

The profile departs from the rail extract at two points, and a reader who knows the core should note both (MUST-DP-6):

  • A member this document does not name is refused, on the body and on a row. The core lets a rail add members of its own because a rail is a system the profile does not control; an Effect Extract is produced by a process the deployment does control (Section 7), and the companion measured what a free member can do to a population (Section 3). A later revision may open this once a channel that needs its own members is measured.

  • A row whose timestampMs falls outside [windowStartMs, windowEndMs) makes the whole extract malformed, refused as effect-outside-window before any signature is checked. The core accepts such a rail extract and names the row (extract-scope-mismatch). Here the extract is the deployment's own document and a window it did not keep is a document it did not produce correctly: a signer applying this schema never produces such an extract, and a verifier refuses one that is presented as a document, whatever else it may also name about its rows. The trade is stated so it can be reversed: a single row out of place fails the whole window closed.

effectHash on a row is computed by the extract's signer over the same octets a Decider hashes for its effectHash claim: the content as the channel carried it. A deployment MUST state those octets once for both sides; the companion's example channel hashes the UTF-8 octets of the message text.

5.2. Authentication and scope

The extract is signed the way a rail extract is signed: Ed25519 [RFC8032] over the UTF-8 octets of the [RFC8785] encoding of the body, with the signature as base64 and the signer's public key as a SubjectPublicKeyInfo PEM beside the body, neither inside the signed octets. It is a JSON document with a detached signature, not a COSE object, and like the rail extract it has no media type: the core registers names for the objects whose content type is checked inside a protected header, and an extract has no such header. A first cut of the companion exported a +cbor name for it that nothing used; the name is withdrawn with this revision. Section 9.3 of [CEDULON] applies unchanged: a signature proves internal consistency and not origin; the verifier MUST hold the extract signer's key out of band and MUST compare keys as SubjectPublicKeyInfo DER; with no key held the guarantee is conditional and unauthenticated-extract is reported; with a key held, an extract that does not verify under it is extract-key-mismatch and its rows are not reconciled (settlement-comparison-skipped, the core's name for the same condition).

The extract is scoped to one Decider, one channel, and one window, and Section 9.4 of [CEDULON] applies with the nouns renamed: a verifier that knows which Decider, channel, and window it audits MUST check the extract against them and MUST fail closed on a mismatch (extract-scope-mismatch); one that has not stated the window MUST report unstated-audit-window, one that has not stated the Decider or the channel MUST report unstated-audit-scope, and in either case the guarantee is conditional. The strongest line this profile can print, a balanced audit under an unconditional guarantee, is true of one Decider, on one channel, over one window, and a report that carries it MUST also carry those three (MUST-DP-7).

6. Reconciliation

The verification algorithm of Section 11.4 of [CEDULON] runs unchanged over this population: establish the subject, verify the extract, check scope, resolve records against the decider root, walk the chain, index both sides by ref, match, decode and walk the checkpoints, consult the witness if one is supplied, and decide. This section states only what the algorithm reads differently.

6.1. What binds

A Decision Record expects a row when its decision is allow, and expects none when it is a refusal. For a ref that appears once on each side:

  • an allow and a row bind when the row's effectHash equals the record's effectHash; a difference is effect-mismatch (the content that occurred is not the content that was allowed);

  • an allow with no row is decision-without-effect;

  • a row with no record is effect-without-decision;

  • a row whose ref a refusal names is effect-against-refusal.

The last is the finding this profile exists for. A spend audit has no row that should not be there in the same sense: an aborted receipt that still carries its reference and a settlement under that reference is reported by the core as a settlement without a receipt, and it never told the two cases apart. Here a refusal that was followed by the effect it refused is a different fact from an effect nobody decided on, and it has its own name.

A ref that appears more than once on a side is duplicate-ref as in the core, and the repeating reference is then reconciled by count rather than by amount: there is nothing to sum. More rows than records under one reference is effect-without-decision; more records than rows is decision-without-effect.

There is no amount, no currency, no manifest, no terms, and no counterparty axis on this profile. The core's counterparty-unbound scope record is not emitted: effectHash binds the content of the effect itself, which is more than a payee name ever bound on spend, and actor on a row is carried for the reader, not measured. The core's boundary rule applies unchanged: an unmatched item inside the declared clock-skew allowance of a window edge is boundary-deferred, and a closing-edge allow whose ref the following extract names is carried, not a finding.

6.2. Conservation

With |R| the in-scope Decision Records and |E| the effect rows, the identities the core report publishes hold with the words changed:

|R|      = refusals + allows
refusals = deny + defer
allows   = matched + deferred + carried
           + unmatched + repeated + unreconciled
|E|      = matched + deferred
           + unmatched + repeated + unreconciled
matched on |R| equals matched on |E|

A report under this profile MUST publish these counts and MUST name the population they were computed over (MUST-DP-8), for the reason the core gives: a report whose counts do not close is a report that lost a record somewhere, and a reader is entitled to see that without re-running the audit. The report publishes refusals as one count, the core's aborted; the split of that count into deny and defer is the checkpoint's totals (Section 4.4), not a counter of the report.

6.3. Finding codes

The identifiers below are for diagnostic output and are not an interoperability surface, as Section 11.5 of [CEDULON] states for the core's codes. Four are new to this profile:

Table 5
Code Effect Meaning
decision-without-effect audit fails An allow names a reference under which no effect occurred, or a reference had more records than rows
effect-without-decision audit fails An effect occurred under a reference no Decision Record names, or a reference had more rows than records
effect-against-refusal audit fails An effect occurred under a reference a refusal names
effect-mismatch audit fails The effect that occurred does not carry the content hash the allow named

The remaining codes a report under this profile can carry are the core's, with the same effect on the verdict and the guarantee: duplicate-ref, boundary-deferred, receipt-chain-break for a break in the Decider's chain (signature, rule, or link), checkpoint-total-mismatch, checkpoint-head-mismatch, window-coverage, equivocation, unauthenticated-extract, extract-key-mismatch, extract-scope-mismatch, extract-settlement-mismatch (a caller-supplied row list that disagrees with the extract), settlement-comparison-skipped, trust-key-unreadable, unauthenticated-issuer, issuer-key-mismatch, carried-key-mismatch, unstated-audit-window, unstated-audit-scope, the witness codes, and malformed-policy-hash; the other hash claims of a Decision Record are refused at verification (Section 4.2) and reach the chain walk rather than a malformed-hash code. Two code names carry a spend noun onto this profile (receipt-chain-break, settlement-comparison-skipped); they are kept so that one catalogue serves both populations, and a later revision may add decision-side aliases. The codes the core defines for a Trade Manifest, a payee countersignature, a beneficiary, or a counterparty are not reachable on this profile.

The sentences a report prints beside those codes are another matter. An operator reading a decision report SHOULD NOT have to translate "settlement" as "effect" or "receipt" as "decision record"; an implementation SHOULD print the sentence in the population's own words, and the companion holds that under a test that runs every conformance case and refuses a spend noun in any decision sentence. Counter names in a returned structure are diagnostic and MAY keep the core's names.

7. Trust roots

This profile has two roots, filling the core's issuer root and rail root (Sections 10.1 and 9.3 of [CEDULON]):

The decider root:

The key under which Decision Records and their checkpoints are attested. Everything Section 10.1 of the core states for the issuer root applies: a pinned key attests by signature, a carried key is not an identity, a record under another key is issuer-key-mismatch and covers nothing, and with no pin unauthenticated-issuer makes the guarantee conditional.

The effect-extract root:

The key under which the Effect Extract is attested. Everything Section 9.3 of the core states for the rail key applies.

The core's payee, witness, decision-token, and manifest roots are not used by this profile, except that a transparency witness MAY hold the Decider's checkpoints exactly as it holds a Receipt Issuer's, with the witness root and codes of the core unchanged.

What the two roots do not cover is the relation between them. The profile's claim is only as strong as the independence of the party that signs the Effect Extract from the party that signs the Decision Records. Where the channel operator signs an export of its own log, the extract root is that operator's key and the independence is the operator's. Where the channel operator signs nothing, which is the common case for a messaging platform, the extract is produced by a capture process the deployment runs, and the deployment is stating, by pinning that process's key, that the process is not the Decider and cannot be told what to omit. A deployment MUST state which of the two it has, and a verifier MUST treat the guarantee as conditional where the extract root and the decider root are, or may be, the same party (MUST-DP-9). The companion cannot measure that from the keys alone; two keys can be held by one hand.

8. Security Considerations

The core's threat analysis (Section 16 of [CEDULON]) applies where the nouns carry over: forgery and repudiation of a signed record (T4), key leakage (T7), and suppression of checkpoints (T11) are the same threats against a Decider that they are against a Receipt Issuer, and the controls are the same. The threats below are the ones this population adds or sharpens.

8.1. D1: An effect occurs against a refusal

The agent, or something acting through its channel access, does what the Decider refused. This is the threat the profile exists for. A Decision Record for the refusal, with the reference it refused, and an authenticated extract that carries an effect under that reference make the event effect-against-refusal, and the audit fails. A refusal that carried no reference cannot support this finding; the effect is then effect-without-decision, which also fails the audit but does not say it was refused. A Decider SHOULD carry the reference on a refusal whenever the channel assigns one before the decision.

8.2. D2: Effects without decisions

Something acts on the channel that never asked. Every such effect is effect-without-decision. The control is the extract's completeness, which is the extract root's independence (Section 7); a capture process the Decider controls can leave the effect out.

8.3. D3: Substitution of content

The Decider allows one content and the channel carries another. The allow's effectHash and the row's effectHash are computed over the same octets, and a difference is effect-mismatch. The control fails open if the two sides hash different octets, which is why a deployment MUST state the octets once for both (Section 5.1).

8.4. D4: The Decider signs below its own rules

A Decider produces a well-formed signature over a claim map that breaks a rule this profile states: an allow with no reference or no content hash, a refusal with a content hash, a hash outside the grammar. Every such record is a record the reconciliation cannot close or would close wrongly. The verifier applies the rules on the decoded payload (MUST-DP-3) and walks the chain over every record that claims the pin (MUST-DP-5), so the record is refused and named rather than attested or dropped.

8.5. D5: Equivocation on the record chain

The Decider signs two decisions for one request, or presents a record twice, and offers each to a different reader. The chain (MUST-DP-5) makes the second record unlinkable: it names the same predecessor as the first, or none, and the walk reports the break. The epoch checkpoint totals, held by a witness where one is used, close the other route.

8.6. D6: The class of the effect is not bound

A Decision Record names a reference and a content hash and does not name the class of effect it allowed. A row of a different class under the same reference and the same content hash matches. This is a known gap of this revision: the record has no claim for the class, and adding one is a claim-set change. A deployment whose channel assigns references per class closes it by construction; one whose references are shared across classes does not, and SHOULD say so in its statement of what it hashes.

8.7. D7: Silent defaults in capture

The process that turns a channel's log into Decision Records or Effect Extract rows fills a missing value with a default, and the default hashes to something. An allow with no stated content that is hashed as the empty string produces a record that will match an empty effect and mismatch every real one, with no finding that says the content was never stated. Such a process MUST refuse the line by name rather than fill it (MUST-DP-10). The companion's example adapter did fill it until it was measured, and refuses it now.

8.8. D8: The capture process is the Decider

The party that produces the Effect Extract is, or answers to, the party that signed the Decision Records. Every finding in D1 and D2 can then be made to disappear by omission, and no signature check detects it. This is the independence statement of Section 7 (MUST-DP-9), and it is a deployment fact the profile can name but not prove. A verifier that holds both roots and cannot state their independence has a conditional result, and MUST say so.

9. Privacy Considerations

A Decision Record carries no request content and no effect content: hashes of both, an opaque subject identifier, and a reason code. The Effect Extract carries a reference, a class, a content hash, a time, and optionally the identifier of the party the effect reached. The core's Privacy Considerations (Section 15 of [CEDULON]) apply to what a transparency witness is given.

Two points are specific to this population. A content hash over a short text is a fingerprint of that text: a reader who can guess the message can confirm the guess. This revision hashes the plain content octets, as the companion does, so that the two sides need no shared secret to agree; a keyed or salted construction that would defeat the guess is a claim-set change and is not defined here. A deployment whose effects are short and guessable SHOULD treat the extract and the records as confidential to the audit. The subject and actor identifiers are opaque to the profile but need not be opaque to a reader; a deployment SHOULD pseudonymize them before either object leaves its control.

10. IANA Considerations

This document requests the registration of one media type in the "Media Types" registry [RFC6838], in the standards tree, carrying the +cbor structured syntax suffix that [RFC8949] registers, on the terms Section 17 of [CEDULON] states for that document's six: it names the one COSE_Sign1 object this document defines and is checked inside that object's protected header, which is why the name cannot stay unregistered while that check stands. The Effect Extract is a JSON document with a detached signature and has no media type (Section 5.2). Registration in the standards tree requires IETF approval; until then, an implementation outside a closed deployment should treat the name as a placeholder that a registration may change. The provisional registration procedure of [RFC6838] Section 5.2.1 is available to an Internet-Draft, and a provisional entry, if one is made, is superseded by the registration this section requests.

The claim labels this document assigns, -70501 through -70512 (Section 4.1), lie in the Private Use range of the "CBOR Web Token (CWT) Claims" registry [RFC8392], integer values less than -65536, and this document requests no assignment for them.

No other IANA action is requested.

10.1. application/cedulon-decision-record+cbor

Type name:

application

Subtype name:

cedulon-decision-record+cbor

Required parameters:

N/A

Optional parameters:

N/A

Encoding considerations:

binary. A COSE_Sign1 structure [RFC9052] in deterministic CBOR [RFC8949], untagged, as profiled in Section 4 and in Section 6 of [CEDULON].

Security considerations:

See Section 8 of this document. The object is signed by the party under audit; its evidentiary weight depends on the verifier holding the decider key out of band (Section 7) and on the verifier applying the claim rules of Section 4.2 itself, never on a key the object carries or on the signer's word that the rules were applied.

Interoperability considerations:

The claim set is a CBOR map with the labels and types stated in Section 4.1, encoded per [RFC8949] Section 4.2.1. A decoder refuses a duplicate key, an input beyond its stated bounds, and a non-empty unprotected header by name rather than accepting it, as Section 6 of [CEDULON] requires of every Cedulon object. A Decision Record and a Decision Token are distinct objects with distinct content types and are never accepted for one another.

Published specification:

This document, Section 4.

Applications that use this media type:

Policy decision points and other deciders that log the decisions they take about an agent's actions, and auditors that reconcile those logs against the channels the actions occurred on.

Fragment identifier considerations:

N/A

Additional information:

Deprecated alias names for this type: N/A. Magic number(s): N/A. File extension(s): N/A. Macintosh file type code(s): N/A.

Person and email address to contact for further information:

Emek Can Dogru, e.dogru@cedulon.com

Intended usage:

COMMON

Restrictions on usage:

N/A

Author:

Emek Can Dogru

Change controller:

IETF

11. Implementation Status

This section is to be removed before publishing as an RFC.

RFC 7942 [RFC7942] note.

Implementation:

The profile is carried by the core document's companion implementation at https://github.com/dogrucanemek-alt/cedulon, on the same reconciler that implements the core, selected by a profile object rather than by a second code path. As of the commit this revision was written against, the tree carries the Decision Record and Effect Extract objects, the profile, eighteen conformance cases covering the rules and departures this document states, and four offline fixtures for one example channel, a direct-message reply log. The spend behaviour of the same reconciler is held byte for byte by a golden file of fifteen cases generated from the source before the profile seam was added.

Maturity:

Prepared, not published. The code is on the companion's default branch and in no released package. Before merge the branch was read twice: by the author's own gate, re-running it from a second worktree, and by an outside model reading the whole diff and barred from changing it. The two readings found four defects in the first cut of this profile, each recorded in the companion's review log: a verifier that did not apply the signer's claim rules (D4), a spend-side crash on the wrong document (Section 3), a spend warning leaking onto decision reports, and a document that counted its own cases wrong. All four were closed with a test that was red before the fix. A third pass moved the report vocabulary onto the profile.

Not measured: a live channel log. The example adapter maps a proposed line format for a direct-message bridge; the bridge's actual field names were not read when this revision was written, and the adapter is written so that only its two line-mapping functions should move when they are. No independent implementation of this profile is known to the author; the one outside reading ran the companion's own suite, which is the same code agreeing with itself on a second machine.

12. References

12.1. Normative References

[CEDULON]
Dogru, E. C., "Cedulon: An Audit Layer for Agent-to-Agent Commerce", Work in Progress, Internet-Draft, draft-dogru-cedulon-08, , <https://datatracker.ietf.org/doc/html/draft-dogru-cedulon-08>.
[RFC2119]
Bradner, S., "Key words for use in RFCs to Indicate Requirement Levels", BCP 14, RFC 2119, DOI 10.17487/RFC2119, , <https://www.rfc-editor.org/rfc/rfc2119>.
[RFC6234]
Eastlake 3rd, D. and T. Hansen, "US Secure Hash Algorithms (SHA and SHA-based HMAC and HKDF)", RFC 6234, DOI 10.17487/RFC6234, , <https://www.rfc-editor.org/rfc/rfc6234>.
[RFC6838]
Freed, N., Klensin, J., and T. Hansen, "Media Type Specifications and Registration Procedures", BCP 13, RFC 6838, DOI 10.17487/RFC6838, , <https://www.rfc-editor.org/rfc/rfc6838>.
[RFC8032]
Josefsson, S. and I. Liusvaara, "Edwards-Curve Digital Signature Algorithm (EdDSA)", RFC 8032, DOI 10.17487/RFC8032, , <https://www.rfc-editor.org/rfc/rfc8032>.
[RFC8174]
Leiba, B., "Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words", BCP 14, RFC 8174, DOI 10.17487/RFC8174, , <https://www.rfc-editor.org/rfc/rfc8174>.
[RFC8392]
Jones, M., Wahlstroem, E., Erdtman, S., and H. Tschofenig, "CBOR Web Token (CWT)", RFC 8392, DOI 10.17487/RFC8392, , <https://www.rfc-editor.org/rfc/rfc8392>.
[RFC8785]
Rundgren, A., Jordan, B., and S. Erdtman, "JSON Canonicalization Scheme (JCS)", RFC 8785, DOI 10.17487/RFC8785, , <https://www.rfc-editor.org/rfc/rfc8785>.
[RFC8949]
Bormann, C. and P. Hoffman, "Concise Binary Object Representation (CBOR)", STD 94, RFC 8949, DOI 10.17487/RFC8949, , <https://www.rfc-editor.org/rfc/rfc8949>.
[RFC9052]
Schaad, J., "CBOR Object Signing and Encryption (COSE): Structures and Process", STD 96, RFC 9052, DOI 10.17487/RFC9052, , <https://www.rfc-editor.org/rfc/rfc9052>.
[RFC9864]
Jones, M.B. and O. Steele, "Fully-Specified Algorithms for JSON Object Signing and Encryption (JOSE) and CBOR Object Signing and Encryption (COSE)", RFC 9864, DOI 10.17487/RFC9864, , <https://www.rfc-editor.org/rfc/rfc9864>.

12.2. Informative References

[RFC7942]
Sheffer, Y. and A. Farrel, "Improving Awareness of Running Code: The Implementation Status Section", BCP 205, RFC 7942, DOI 10.17487/RFC7942, , <https://www.rfc-editor.org/rfc/rfc7942>.

Acknowledgments

This profile is the first concrete instance of the generalization the core document reserves. The refusal that was followed by the effect it refused, as a finding with its own name, came out of watching a messaging assistant's decision log beside the channel's sent log and finding that the spend vocabulary had no word for it.

Author's Address

Emek Can Dogru
VERAX TEKNOLOJI LIMITED SIRKETI