From 53ef9c70127810030928b4ef88564ad6f0f95da8 Mon Sep 17 00:00:00 2001 From: "Claude (oddkit project)" Date: Thu, 16 Apr 2026 02:20:35 +0000 Subject: [PATCH] fix: governance gaps surfaced by encode implementation bugbot review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Four governance bugs produced four code bugs in PR klappy/oddkit#96. The server had no governance to follow for these cases and improvised. Fixes: 1. Removed bare 'found' from observation trigger words — collided with Learning's 'found that' during fallback regex classification 2. Added fallback: true to observation.md frontmatter — observation is the canonical fallback for unmatched paragraphs 3. Added ## Fallback Behavior section to how-to-write-encoding-types.md — specifies how fallback type is resolved via frontmatter 4. Added ## Scoring Algorithm section to how-to-write-encoding-types.md — centrally defines score→level mapping (strong=max, adequate=60%+, weak=40%+, insufficient<40%) 5. Added ## Context vs Input section to how-to-write-encoding-types.md — input generates artifacts, context only informs quality scoring Prompt over code requires complete governance. These gaps caused the server to improvise, and bugbot caught the improvisations. --- .../how-to-write-encoding-types.md | 54 +++++++++++++++++++ odd/encoding-types/observation.md | 3 +- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/odd/encoding-types/how-to-write-encoding-types.md b/odd/encoding-types/how-to-write-encoding-types.md index b9a904cc..6f8bfef1 100644 --- a/odd/encoding-types/how-to-write-encoding-types.md +++ b/odd/encoding-types/how-to-write-encoding-types.md @@ -181,6 +181,60 @@ These sections improve the article's value for human readers and model teaching. --- +## Fallback Behavior — What Happens When No Type Matches + +When a paragraph in unstructured input matches no type's trigger regex, the server uses a fallback type. The fallback type is determined by governance, not hardcoded in the server. + +A type declares itself as the fallback by including `fallback: true` in its frontmatter: + +```yaml +--- +uri: klappy://odd/encoding-types/observation +fallback: true +--- +``` + +Resolution order: +1. If exactly one type has `fallback: true`, that type is the fallback +2. If multiple types declare `fallback: true`, the first one discovered wins (alphabetical by filename) +3. If no type declares `fallback: true`, the server uses the first type discovered as fallback + +The recommended convention is to mark **Observation (O)** as the fallback. An unclassified paragraph is raw content without interpretation — semantically, that's what an Observation is. This convention is followed by the default OLDC+H types. + +--- + +## Scoring Algorithm — How Score Maps to Quality Level + +Each type's governance doc defines N quality criteria. Each criterion the artifact satisfies adds 1 to the score, so `max_score` equals the number of criteria. + +The server maps score to quality level using these thresholds: + +| Condition | Level | +|---|---| +| `score == max_score` | strong | +| `score >= ceil(max_score * 0.6)` | adequate | +| `score >= ceil(max_score * 0.4)` | weak | +| otherwise | insufficient | + +This algorithm works for any `max_score` value. A type with 4 criteria: strong=4, adequate≥3, weak≥2, insufficient<2. A type with 1 criterion: strong=1, insufficient=0 (the percentage thresholds round up so intermediate levels don't apply). + +Individual type docs may include a `## Quality Levels` table showing the specific numbers for that type's `max_score`, but the algorithm itself is defined here once. + +--- + +## Context vs Input — How Supplementary Context Is Handled + +The encode action accepts two parameters: `input` (the primary content) and `context` (supplementary background). They serve different purposes: + +- **`input`** is parsed into artifacts. Every row or paragraph in `input` generates an encoded artifact. +- **`context`** is not parsed into separate artifacts. Context supplies information that informs quality scoring — for example, a decision's rationale or alternatives mentioned in context count toward the Decision's quality score — but context itself never becomes a standalone artifact. + +The server concatenates `input` and `context` only for quality scoring passes. For type detection and artifact parsing, only `input` is used. + +This distinction matters because callers often want to provide background ("the meeting discussed X, Y, and Z") without generating separate artifacts for every background sentence. Context is metadata. Input is content. + +--- + ## Writing a Custom Encoding Type Custom types follow this identical structure. A pastoral knowledge base adding "Prayer Request" writes: diff --git a/odd/encoding-types/observation.md b/odd/encoding-types/observation.md index 65c45512..69efd727 100644 --- a/odd/encoding-types/observation.md +++ b/odd/encoding-types/observation.md @@ -12,6 +12,7 @@ date: 2026-04-15 derives_from: "docs/oddkit/proactive/dolche-vocabulary.md" governs: "oddkit_encode parsing and quality scoring for type O" status: active +fallback: true --- # Encoding Type: Observation (O) @@ -48,5 +49,5 @@ Observations describe reality as encountered, not reality as theorized. They are ## Trigger Words (Fallback Classification) ``` -observed, noticed, saw, found, measured, detected, appeared, showed +observed, noticed, saw, measured, detected, appeared, showed ```