From c3645e6f737b3c758bc36e90f23ca4cdaf10b252 Mon Sep 17 00:00:00 2001 From: Nick Bianchi Date: Mon, 16 Mar 2026 10:37:47 +0000 Subject: [PATCH 1/2] fix: include Authority (A) in all entity type definitions The canonical governance (chittycanon://gov/governance#core-types) mandates 5 entity types: P/L/T/E/A. Several code paths only accepted 4, rejecting Authority (A): - config/index.js entityTypes map - services/vrf-generator.js validation - agents/validator.js validTypes array Also fixes the pipeline to map "context" and "agent" purposes to Person (P) instead of defaulting to Thing (T), and respects explicit entity_type query parameter override in the API handler. Co-Authored-By: Claude Opus 4.6 --- src/agents/validator.js | 4 ++-- src/api/index.js | 6 ++++-- src/config/index.js | 4 +++- src/pipeline/index.js | 15 +++++++++++++-- src/services/vrf-generator.js | 5 +++-- 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/agents/validator.js b/src/agents/validator.js index 8eeacd9..7973c71 100644 --- a/src/agents/validator.js +++ b/src/agents/validator.js @@ -81,8 +81,8 @@ export class ValidatorAgent { return { valid: false, reason: "Invalid sequential ID" }; } - // Type: valid entity types (single letters) - const validTypes = ["P", "L", "T", "E"]; + // @canon: chittycanon://gov/governance#core-types + const validTypes = ["P", "L", "T", "E", "A"]; if (!validTypes.includes(type)) { return { valid: false, reason: "Invalid entity type" }; } diff --git a/src/api/index.js b/src/api/index.js index 0a73007..502895e 100644 --- a/src/api/index.js +++ b/src/api/index.js @@ -65,7 +65,8 @@ export class ChittyAPI { method: 'GET', handler: async (request, url) => { const purpose = url.searchParams.get('for') || 'general'; - return await this.pipeline.process(request, purpose); + const entityTypeOverride = url.searchParams.get('entity_type') || null; + return await this.pipeline.process(request, purpose, entityTypeOverride); } }, @@ -244,7 +245,8 @@ export class ChittyAPI { 'P': 'Person', 'L': 'Location', 'T': 'Thing', - 'E': 'Event' + 'E': 'Event', + 'A': 'Authority' } }, YM: { diff --git a/src/config/index.js b/src/config/index.js index 90a8e40..c7f785a 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -75,11 +75,13 @@ export const ChittyConfig = { '8': 'International Waters', '9': 'Digital/Virtual' }, + // @canon: chittycanon://gov/governance#core-types entityTypes: { 'P': 'Person', 'L': 'Location', 'T': 'Thing', - 'E': 'Event' + 'E': 'Event', + 'A': 'Authority' }, trustLevels: { '0': 'L0 - Unverified', diff --git a/src/pipeline/index.js b/src/pipeline/index.js index 11a2357..e573e09 100644 --- a/src/pipeline/index.js +++ b/src/pipeline/index.js @@ -21,10 +21,11 @@ export class ChittyPipeline { * @param {string} purpose - Purpose of ID request (e.g., 'work-item', 'document') * @returns {Promise} */ - async process(request, purpose = "general") { + async process(request, purpose = "general", entityTypeOverride = null) { const context = { request, purpose, + entityTypeOverride, timestamp: new Date().toISOString(), stages: {}, }; @@ -306,10 +307,16 @@ class GenerationStage { try { // Prepare parameters for id.chitty.cc service + // Explicit entity_type override takes precedence over purpose-based mapping + const validEntityTypes = ["P", "L", "T", "E", "A"]; + const override = context.entityTypeOverride; + const entityType = (override && validEntityTypes.includes(override.toUpperCase())) + ? override.toUpperCase() + : this.mapPurposeToEntityType(purpose); const params = { region: this.determineRegion(user), jurisdiction: this.determineJurisdiction(user), - entityType: this.mapPurposeToEntityType(purpose), + entityType, trustLevel: trustLevel.toString(), metadata: { userId: user.id, @@ -399,12 +406,16 @@ class GenerationStage { return jurisdictionMap[user.country] || "INT"; } + // @canon: chittycanon://gov/governance#core-types mapPurposeToEntityType(purpose) { const mapping = { person: "P", location: "L", thing: "T", event: "E", + authority: "A", + context: "P", // Contexts are Person (P, Synthetic) — actors with agency + agent: "P", // Agents are Person (P, Synthetic) — actors with agency "work-item": "T", document: "T", asset: "T", diff --git a/src/services/vrf-generator.js b/src/services/vrf-generator.js index 59ca71e..46be9e5 100644 --- a/src/services/vrf-generator.js +++ b/src/services/vrf-generator.js @@ -188,8 +188,9 @@ export class VRFGenerator { throw new Error("Namespace must be exactly 3 letters"); } - if (!["P", "L", "T", "E"].includes(entityType)) { - throw new Error("Entity type must be P, L, T, or E"); + // @canon: chittycanon://gov/governance#core-types + if (!["P", "L", "T", "E", "A"].includes(entityType)) { + throw new Error("Entity type must be P, L, T, E, or A"); } if (!region || region < "1" || region > "9") { From c8dfaa30074a38a97016c6358da52f4ae97a1bbd Mon Sep 17 00:00:00 2001 From: Nick Bianchi Date: Tue, 17 Mar 2026 00:54:05 +0000 Subject: [PATCH 2/2] =?UTF-8?q?fix:=20respect=20entity=5Ftype=20param=20an?= =?UTF-8?q?d=20map=20purpose=E2=86=92type=20for=20context=20mints?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The entity_type query parameter was being ignored — only `type` and `for` were read. When `for=context`, the raw value "context" had no mapping in ENTITY_TYPES, causing fallback to T (Thing) instead of P (Person). Changes: - Add entity_type as highest-priority param (explicit override) - Add PURPOSE_ENTITY_MAP for purpose values (context→person, claude→person) - Fixes contexts always getting T instead of P Ref: chittycanon://gov/governance#core-types Co-Authored-By: Claude Opus 4.6 (1M context) --- worker.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/worker.js b/worker.js index e47bcf9..a332966 100644 --- a/worker.js +++ b/worker.js @@ -111,11 +111,17 @@ function getErrorFromId(chittyId) { }; } +// Purpose-to-entity-type mapping for non-type values passed via ?for= +// @canon: chittycanon://gov/governance#core-types +const PURPOSE_ENTITY_MAP = { context: 'person', claude: 'person', 'work-item': 'thing', document: 'thing', general: 'thing' }; + // Direct ChittyID generation handler - delegates to ChittyMint with fallback async function handleDirectChittyIdGeneration(url, env, request) { - const rawType = (url.searchParams.get('type') || url.searchParams.get('for') || 'thing').toLowerCase(); - // Accept both code-form (P/L/T/E/A) and word-form (person/place/thing/event/authority) - const entityTypeParam = CODE_TO_WORD[rawType] || rawType; + // Priority: explicit entity_type > type > for (with purpose mapping) > default 'thing' + const explicitType = url.searchParams.get('entity_type'); + const rawType = (explicitType || url.searchParams.get('type') || url.searchParams.get('for') || 'thing').toLowerCase(); + // Accept code-form (P/L/T/E/A), word-form (person/place/thing/event/authority), or purpose (context/claude) + const entityTypeParam = CODE_TO_WORD[rawType] || PURPOSE_ENTITY_MAP[rawType] || rawType; // Extract auth token if present (forward to ChittyMint) const authHeader = request?.headers?.get('Authorization');