Code, design and documents 5 files
docs/DATA-MAINTENANCE.md +4 −0
@@ -239,4 +239,8 @@ context:
a binding ruling requires more than detection. Give the limit and its unit, the penalty and
licence consequences, and any separate rule for medical patients, novice or professional drivers.
+- Use `driving.status: unknown` when a reviewed law mentions drug-driving but the cannabis-specific
+ conviction trigger remains unverified. Keep the sourced explanation; the map leaves it hatched.
+ A `limit` classification needs a numerical THC concentration, unit and supporting primary
+ source, not merely the phrase "prescribed limits" or an alcohol threshold.
- **`visitors.status`** is whether someone who does not live in the country can get cannabis
legally: `open` (same terms as residents), `residents` (legal supply is for residents only) or
docs/research/issue-corrections-186-204-2026-10-27.md +13 −0
@@ -50,2 +50,15 @@ The classification is not a claim that the entire plant has been rescheduled as
narcotic. Existing explanation of prescription access and practical shop closures
remains. Added the direct official notice to visitor sources.
+
+## #194 — Verified driving trigger and numerical limits
+
+Read Kenya's 2026 Drink-Driving Rules in the normal browser at Kenya Law, regulation
+3: the prescribed concentrations are expressly blood-alcohol concentrations. Section
+44's general prescribed-limits phrase is insufficient to label a fixed THC offence.
+Added an explicit unknown reviewed trigger, hatched on the map, retaining the cited
+legal text and penalties without inventing an impairment or detectable-THC test.
+No claim that drug driving is lawful. The regression audits every fixed-limit
+profile for a numerical concentration and source. That audit found New Zealand's
+existing fixed-threshold description lacked the number: read the official 2025/247
+notice and added 5 ng/mL THC in oral fluid, an evidential laboratory threshold,
+not the separate roadside device threshold. Its source/commencement is recorded.
scripts/profile-claims.test.mjs +11 −0
@@ -376,2 +376,13 @@ test('Thailand medical-only flower status agrees with its explanation (#193)', (
assert.match(th.context.planting.text, /seed|plant/i);
});
+
+// Issue #194
+test('fixed THC classes require numerical evidence; Kenya remains unverified (#194)', () => {
+ assert.equal(country('ke').context.driving.status, 'unknown');
+ for (const name of fs.readdirSync(path.join(root,'countries')).filter(n=>n.endsWith('.yaml'))) {
+ const p = country(name.slice(0,-5)), d = p.context?.driving;
+ if (d?.status !== 'limit') continue;
+ assert.match(d.text, /\d+(?:\.\d+)?\s*(?:nanograms?|microgram(?:me)?s?|ng|µg|mg)/i, name);
+ assert.ok(d.sources.some(k => p.sources[k]?.url), name+' needs a source for its numerical rule');
+ }
+});
src/components/HomePage.astro +2 −2
@@ -146,5 +146,5 @@ const LAW_SECTIONS = {
const MAP_SECTIONS = { ...LAW_SECTIONS, ...STATUS_SECTIONS };
const STATUS_SCALES = Object.fromEntries(Object.entries(MAP_SECTIONS).map(([key, section]) => [key, { name: section.name,
- scale: Object.fromEntries(Object.entries(section.statuses).map(([k, v]) => [k, { label: v.label, help: v.help, color: `var(--t${section.tiers[k]})` }])) }]));
+ scale: Object.fromEntries(Object.entries(section.statuses).map(([k, v]) => [k, { label: v.label, help: v.help, color: section.tiers[k] == null ? "url(#hatch)" : `var(--t${section.tiers[k]})` }])) }]));
// the map's views in groups, as [metric, label]: the tabs and rows of the view picker
const datasetViews = (group) => MAPPED.filter((ds) => ds.map.group === group).map((ds) => [`data:${ds.id}`, ds.map.label]);
@@ -519,5 +519,5 @@ const columnGroups = [["Shown by default", BASE_COLUMNS], ...["Score segments",
<script type="application/json" id="cfi-freedom-years" set:html={JSON.stringify(FREEDOM_YEARS)} />
<script type="application/json" id="cfi-price-scale" set:html={JSON.stringify(PRICE_SCALE)} />
- <script type="application/json" id="cfi-planting" set:html={JSON.stringify({ fields: PLANTING_FIELDS, scales: PLANTING_SCALES, sections: STATUS_SCALES, subs: Object.fromEntries(Object.entries(MAP_SECTIONS).map(([key, section]) => [key, section.complete ? section.sub : `${section.sub} Hatched countries have not been researched yet. Not part of the score.`])) })} />
+ <script type="application/json" id="cfi-planting" set:html={JSON.stringify({ fields: PLANTING_FIELDS, scales: PLANTING_SCALES, sections: STATUS_SCALES, subs: Object.fromEntries(Object.entries(MAP_SECTIONS).map(([key, section]) => [key, section.complete ? section.sub : `${section.sub} ${key === "driving" ? "Hatched countries have an unverified trigger or have not been researched yet." : "Hatched countries have not been researched yet."} Not part of the score.`])) })} />
<script type="application/json" id="cfi-segments" set:html={JSON.stringify(SEGMENTS.map((s) => ({ name: s.name, desc: s.desc, levels: s.levels })))} />
src/lib/segment-ids.js +3 −2
@@ -32,4 +32,5 @@ export const CLUBS_STATUS = {
// Driving after use: what the law needs to convict a driver. Not part of the score.
export const DRIVING_STATUS = {
+ unknown: { label: "Drug-driving trigger unverified", tone: "grey", help: "Drug-driving rules were reviewed, but no cannabis-specific offence trigger or THC cutoff was established" },
impairment: { label: "Impairment must be shown", tone: "legal", help: "The reviewed driving offence requires evidence of drug influence or impairment; additional offences may apply" },
capacity: { label: "Capable of affecting driving", tone: "decrim", help: "A conviction needs the drug in a biological sample and proof it was capable of affecting driving. A driving mistake is outside that proof" },
@@ -50,6 +51,6 @@ export const STATUS_SECTIONS = {
sub: "Green means cannabis clubs are regulated or tolerated, orange that they work underground, red that none are known.",
note: "The footing cannabis clubs stand on. Licensed shops and pharmacies are not counted as clubs." },
- driving: { name: "Driving", chip: "Driving", statuses: DRIVING_STATUS, tiers: { impairment: 5, capacity: 4, limit: 3, consumption: 2, zero: 0 },
- sub: "Green marks a drug-influence or impairment offence, light green a rule that needs proof the drug could affect driving, yellow a fixed THC limit, orange a prohibition after consumption, and red a detectable-THC offence. Read each profile for additional rules.",
+ driving: { name: "Driving", chip: "Driving", statuses: DRIVING_STATUS, tiers: { impairment: 5, capacity: 4, limit: 3, consumption: 2, zero: 0, unknown: null },
+ sub: "Green marks a drug-influence or impairment offence, light green a rule that needs proof the drug could affect driving, yellow a fixed THC limit, orange a prohibition after consumption, and red a detectable-THC offence. Hatched means the cannabis-specific trigger is unverified. Read each profile for additional rules.",
note: "What the law needs to convict a driver who has used cannabis." },
visitors: { name: "Visitors and foreigners", chip: "Visitors", statuses: VISITORS_STATUS, tiers: { open: 5, residents: 3, none: 0 },