| { | ||
| "type": "consumer_product.evidence_packet.v0", | ||
| "schema_version": 1, | ||
| "ok": true, | ||
| "observed_at": "2026-07-29T00:00:00.000Z", | ||
| "sections": [ | ||
| { | ||
| "section_id": "forge_facts", | ||
| "section_type": "forge_facts", | ||
| "schema": "consumer_product.producer_section.v1" | ||
| } | ||
| ] | ||
| } |
| { | ||
| "type": "remogram.forge_facts.v1", | ||
| "schema_version": 1, | ||
| "ok": true, | ||
| "observed_at": "2026-07-29T00:00:00.000Z", | ||
| "authority_role": "authoritative", | ||
| "producer": "remogram", | ||
| "repository": { | ||
| "repo_id": "attebury/remogram" | ||
| }, | ||
| "targets": [ | ||
| { | ||
| "kind": "change_request", | ||
| "id": "961" | ||
| } | ||
| ] | ||
| } |
| import { validatePacketEnvelope } from './envelope.js'; | ||
| export const NEUTRAL_EVIDENCE_PROTOCOL_SCHEMA_VERSION = 1; | ||
| export const NEUTRAL_EVIDENCE_CONFORMANCE_PACKET_TYPE = 'neutral.evidence_packet_conformance.v1'; | ||
| export const NEUTRAL_EVIDENCE_AUTHORITY_ROLES = Object.freeze([ | ||
| 'authoritative', | ||
| 'advisory', | ||
| 'validator', | ||
| 'sink', | ||
| 'standard', | ||
| ]); | ||
| export const DEFAULT_FORBIDDEN_PRODUCT_NAMESPACES = Object.freeze([]); | ||
| export const LEGACY_PRODUCER_SECTION_FIELDS = Object.freeze([ | ||
| 'section_id', | ||
| 'section_type', | ||
| 'section_version', | ||
| 'producer_section', | ||
| 'producer_sections', | ||
| ]); | ||
| const PRODUCT_COUPLING_FIELD_PATTERN = /(?:^|_)(?:type|schema|section|corpus|golden|contract|fixture|packet)(?:_|$)/i; | ||
| function isObject(value) { | ||
| return value && typeof value === 'object' && !Array.isArray(value); | ||
| } | ||
| function packetSummary(packet) { | ||
| return { | ||
| type: typeof packet?.type === 'string' ? packet.type : 'unknown', | ||
| schema_version: packet?.schema_version ?? 'unknown', | ||
| ok: typeof packet?.ok === 'boolean' ? packet.ok : false, | ||
| }; | ||
| } | ||
| function issue(code, path, message) { | ||
| return { code, path, message }; | ||
| } | ||
| function namespacePattern(namespace) { | ||
| const escaped = String(namespace).replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); | ||
| return new RegExp(`(?:^|[._/-])${escaped}(?:[._/-]|$)`, 'i'); | ||
| } | ||
| function pathFor(path) { | ||
| return path.length === 0 ? '$' : `$.${path.join('.')}`; | ||
| } | ||
| function walk(value, visitor, path = []) { | ||
| visitor(value, path); | ||
| if (Array.isArray(value)) { | ||
| value.forEach((item, index) => walk(item, visitor, path.concat(String(index)))); | ||
| } else if (isObject(value)) { | ||
| for (const [key, child] of Object.entries(value)) { | ||
| walk(child, visitor, path.concat(key)); | ||
| } | ||
| } | ||
| } | ||
| function collectProductCouplingIssues(packet, namespaces) { | ||
| const issues = []; | ||
| const patterns = namespaces.map(namespacePattern); | ||
| walk(packet, (value, path) => { | ||
| const key = path[path.length - 1] ?? ''; | ||
| const keyPath = pathFor(path); | ||
| if (LEGACY_PRODUCER_SECTION_FIELDS.includes(key)) { | ||
| issues.push(issue('legacy_producer_section_field', keyPath, `Legacy producer-section field "${key}" is not neutral producer packet conformance.`)); | ||
| } | ||
| if (patterns.some((pattern) => pattern.test(key))) { | ||
| issues.push(issue('product_namespace_key', keyPath, `Product-specific namespace in key "${key}" is not neutral producer packet conformance.`)); | ||
| } | ||
| if (typeof value !== 'string') return; | ||
| if (!PRODUCT_COUPLING_FIELD_PATTERN.test(key)) return; | ||
| for (const pattern of patterns) { | ||
| if (pattern.test(value)) { | ||
| issues.push(issue('product_namespace_value', keyPath, `Product-specific namespace in "${value}" is not neutral producer packet conformance.`)); | ||
| } | ||
| } | ||
| }); | ||
| return issues; | ||
| } | ||
| function collectEnvelopeIssues(packet, options) { | ||
| const issues = []; | ||
| try { | ||
| validatePacketEnvelope(packet, { | ||
| expectedType: options.expectedType, | ||
| expectedSchemaVersion: options.expectedSchemaVersion, | ||
| }); | ||
| } catch (error) { | ||
| issues.push(issue('packet_envelope_invalid', '$', error instanceof Error ? error.message : String(error))); | ||
| } | ||
| return issues; | ||
| } | ||
| function collectAuthorityIssues(packet, options) { | ||
| const issues = []; | ||
| const authorityRole = packet?.authority_role ?? packet?.authority?.role ?? null; | ||
| if (options.requireAuthorityRole && authorityRole == null) { | ||
| issues.push(issue('authority_role_missing', '$.authority_role', 'Neutral evidence packets that opt into authority checks must declare an authority role.')); | ||
| } | ||
| if (authorityRole != null && !NEUTRAL_EVIDENCE_AUTHORITY_ROLES.includes(authorityRole)) { | ||
| issues.push(issue('authority_role_invalid', '$.authority_role', `Authority role "${authorityRole}" is not a neutral evidence authority role.`)); | ||
| } | ||
| return issues; | ||
| } | ||
| function normalizeOptions(options = {}) { | ||
| const forbiddenProductNamespaces = options.forbiddenProductNamespaces ?? DEFAULT_FORBIDDEN_PRODUCT_NAMESPACES; | ||
| return { | ||
| expectedType: options.expectedType, | ||
| expectedSchemaVersion: options.expectedSchemaVersion, | ||
| producerId: options.producerId ?? null, | ||
| requireAuthorityRole: options.requireAuthorityRole === true, | ||
| forbiddenProductNamespaces: Array.from(forbiddenProductNamespaces), | ||
| }; | ||
| } | ||
| export function evaluateNeutralEvidencePacket(packet, options = {}) { | ||
| const normalized = normalizeOptions(options); | ||
| const issues = []; | ||
| if (!isObject(packet)) { | ||
| issues.push(issue('packet_not_object', '$', 'Neutral evidence packet must be a JSON object.')); | ||
| } else { | ||
| issues.push(...collectEnvelopeIssues(packet, normalized)); | ||
| issues.push(...collectAuthorityIssues(packet, normalized)); | ||
| issues.push(...collectProductCouplingIssues(packet, normalized.forbiddenProductNamespaces)); | ||
| } | ||
| return { | ||
| ok: issues.length === 0, | ||
| protocol: { | ||
| type: 'neutral_evidence_protocol', | ||
| schema_version: NEUTRAL_EVIDENCE_PROTOCOL_SCHEMA_VERSION, | ||
| owner: 'attepack', | ||
| forbidden_product_namespaces: normalized.forbiddenProductNamespaces, | ||
| }, | ||
| producer: normalized.producerId ? { id: normalized.producerId } : null, | ||
| target_packet: packetSummary(packet), | ||
| issues, | ||
| }; | ||
| } | ||
| export function validateNeutralEvidencePacket(packet, options = {}) { | ||
| const result = evaluateNeutralEvidencePacket(packet, options); | ||
| if (!result.ok) { | ||
| const error = new TypeError(`Neutral evidence packet conformance failed: ${result.issues.map((item) => item.code).join(', ')}`); | ||
| error.code = 'neutral_evidence_packet_invalid'; | ||
| error.issues = result.issues; | ||
| throw error; | ||
| } | ||
| return packet; | ||
| } | ||
| export function buildNeutralEvidenceConformance(packet, options = {}) { | ||
| const result = evaluateNeutralEvidencePacket(packet, options); | ||
| return { | ||
| type: NEUTRAL_EVIDENCE_CONFORMANCE_PACKET_TYPE, | ||
| schema_version: NEUTRAL_EVIDENCE_PROTOCOL_SCHEMA_VERSION, | ||
| ok: result.ok, | ||
| protocol: result.protocol, | ||
| ...(result.producer ? { producer: result.producer } : {}), | ||
| target_packet: result.target_packet, | ||
| issues: result.issues, | ||
| }; | ||
| } |
+4
-2
| { | ||
| "name": "attepack", | ||
| "version": "0.1.0", | ||
| "version": "0.1.1", | ||
| "description": "Shared library for packet envelopes, schema contracts, and error packet normalization across the Forest tool ecosystem", | ||
@@ -9,2 +9,3 @@ "type": "module", | ||
| "src/", | ||
| "fixtures/", | ||
| "README.md" | ||
@@ -18,3 +19,4 @@ ], | ||
| "./receipts": "./src/receipts.js", | ||
| "./diagnostics": "./src/diagnostics.js" | ||
| "./diagnostics": "./src/diagnostics.js", | ||
| "./evidence-protocol": "./src/evidence-protocol.js" | ||
| }, | ||
@@ -21,0 +23,0 @@ "scripts": { |
+24
-2
| # Attepack | ||
| Attepack is a shared library of packet envelope primitives, schema contracts, and error packet normalization routines for the Forest tool ecosystem. | ||
| Attepack is a shared library of packet envelope primitives, schema contracts, and error packet normalization routines for tool ecosystems. | ||
| ## Purpose | ||
| Across the Forest ecosystem, tools emit and consume structured JSON packets (e.g. `remogram.forge_facts.v1`, `waylane.execution_facts.v1`, `verigram.work_judgment.v1`, `atteway.audit_view_model.v1`). Attepack standardizes these packet envelopes and error structures to eliminate duplicate parsing and prevent schema drift. | ||
| Across a tool ecosystem, public tools such as Remogram, Skillpress, and ReleasePress exchange structured JSON packets (e.g. `remogram.forge_facts.v1`, `skillpress.capability_manifest.v1`, `release.evidence_manifest.v1`, `consumer.audit_view_model.v1`). Attepack standardizes these packet envelopes and error structures to eliminate duplicate parsing and prevent schema drift. | ||
@@ -15,2 +15,3 @@ ## Modules | ||
| | `attepack/envelope` | Enforces packet envelope validation (`type`, `schema_version`, `observed_at`, `ok`) | | ||
| | `attepack/evidence-protocol` | Validates neutral producer-native evidence packet conformance without product-specific schemas | | ||
@@ -35,1 +36,22 @@ ## Install | ||
| ``` | ||
| ## Neutral Evidence Protocol | ||
| Producer tools should validate their own native packets against the neutral | ||
| evidence protocol instead of importing downstream product schemas or goldens. | ||
| Downstream products may consume, compose, archive, report, and evaluate policy | ||
| over those packets; they are not the protocol owner. | ||
| ```js | ||
| import { validateNeutralEvidencePacket } from 'attepack/evidence-protocol'; | ||
| validateNeutralEvidencePacket({ | ||
| type: 'remogram.forge_facts.v1', | ||
| schema_version: 1, | ||
| ok: true, | ||
| authority_role: 'authoritative' | ||
| }); | ||
| ``` | ||
| Attepack rejects legacy producer-section fields by default. To reject coupling | ||
| to a downstream product namespace, pass `forbiddenProductNamespaces`. |
+11
-0
@@ -38,1 +38,12 @@ export { | ||
| } from './diagnostics.js'; | ||
| export { | ||
| NEUTRAL_EVIDENCE_PROTOCOL_SCHEMA_VERSION, | ||
| NEUTRAL_EVIDENCE_CONFORMANCE_PACKET_TYPE, | ||
| NEUTRAL_EVIDENCE_AUTHORITY_ROLES, | ||
| DEFAULT_FORBIDDEN_PRODUCT_NAMESPACES, | ||
| LEGACY_PRODUCER_SECTION_FIELDS, | ||
| evaluateNeutralEvidencePacket, | ||
| validateNeutralEvidencePacket, | ||
| buildNeutralEvidenceConformance, | ||
| } from './evidence-protocol.js'; |
24947
46.57%11
37.5%650
41%56
64.71%