CanPUFF canpuff.org

canpuff.org Edibles profile draft r1 source 

CanPUFF Edibles Profile

Version 1.0 — DRAFT r1 (2026-10-10) · Companion to CanPUFF Core v1

This profile defines how a CanPUFF vault records edibles: cannabis products that are eaten, counted in pieces, and measured in milligrams, rather than inhaled and weighed (Core §1.2). It adds fields to existing Core objects. It adds no object types, no directories and no files.

Implementing this profile is OPTIONAL, and no application implements it yet; it is published so that one can. Its fields are ordinary unknown fields to a Core reader, which ignores them and preserves them on write-back (Core §2). To such a reader an edible dose is a consumption event with no amount, which contributes 0 grams (Core §4.1.1): nothing breaks, and nothing is counted.

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 (RFC 2119, RFC 8174) when, and only when, they appear in all capitals.


1. Scope

This revision covers products counted in pieces, each with a labelled amount of cannabinoid in milligrams: gummies, chocolates, hard candies, capsules, mints, baked goods.

It does not cover products dosed by volume (beverages, tinctures, oils) or applied to the skin; §7 lists what later additive revisions may add. Inhaled products of every form, including pre-rolls and infused pre-rolls, are weighed and belong to Core (Core §5.1.1).

An edible is not a mass-based supply with a different label. It is dosed by the piece, its potency is stated per piece, and it is already activated, so there is no as-sold/total split. That is why it has fields of its own instead of reusing grams and mg/g concentrations: no gram-based total, limit or chart can then mistake pieces for grams.

2. Fields

2.1 supply

Field Type Meaning
category string edible marks the supply as an edible. (category is defined in Core §5.1.1; this profile defines the value edible.)
format string OPTIONAL free text (Core §5.1.1), e.g. “gummy”, “chocolate”, “hard candy”, “capsule”.
unit string OPTIONAL. g (default) or each: the measurement basis of the package. An edible SHOULD use each.
quantity, quantityStart number Pieces remaining and at acquisition; at most two decimal places. Used only with unit: each.

Rules:

2.2 supply.cannabinoids[].mgPerUnit

For a unit: each supply, potency is stated per piece. An entry of the supply’s cannabinoids array (Core §5.1) MAY carry mgPerUnit: the milligrams of that cannabinoid in one piece, 0–10000, at most four decimal places.

2.3 consumption.serving

For a unit: each supply the dose is a number of pieces, not grams. The event records it as serving instead of amount. Only the common fields and at are REQUIRED (Core §4.1); method is optional, so an edible can be logged without choosing a way of consuming it:

{ "type": "consumption", "version": 1, "id": "…", "at": "2026-10-08T19:00:00-07:00",
  "supply": "…", "serving": { "unit": "each", "value": 0.5 } }

2.4 method.defaultServing

A method MAY carry defaultServing ({ "unit": "each", "value": n }), the typical dose it implies for count-based supplies. It is a hint for user interfaces. Core’s categories (Core §5.1.1) can limit a method to edibles: "categories": ["edible"].

3. Derived values (normative)

None of these is stored.

The user’s own serving. Core §4.1.1 applies unchanged with pieces in place of grams, including its rule for an unresolved supply and its precision rule:

userServing = shared.gift ? (supply.sharedSupply ? serving.value : 0)
                          : serving.value / persons          # persons as in Core §4.1.1

Depletion. A writer SHOULD decrement the supply’s quantity by serving.value (floored at 0) in the same logical operation, and reverse or adjust the decrement when the event is edited or deleted, exactly as Core §4.1 does for grams. A supply with sharedSupply: true SHOULD NOT be decremented by default.

THC. thcMg = userServing × mgPerUnit for the THC entry, and thcUnits = thcMg / 5 (Core §4.1.2: 1 unit = 5 mg Δ9-THC). A missing mgPerUnit leaves the dose unknown; it is not zero.

4. Privacy

The journal rules of Core §1.1 and §11 apply unchanged: events that carry serving are journal-tier and private. Privacy-trimmed sharing of a catalog card (Core §11) treats quantity and quantityStart exactly as it treats grams and gramsStart: omit them unless the user opts in to sharing purchase details. category, format and mgPerUnit describe the product, not the person, and are shareable.

5. Working with Core and with other applications

6. Schemas, validation and fixtures

7. Open questions

This is a draft. Not specified in this revision; each would arrive as an additive revision:

Revision history