From 28f95f40c2f5ee6561506e1a47515af13110c3a7 Mon Sep 17 00:00:00 2001 From: PRAMOD B N Date: Sat, 8 Aug 2026 04:25:13 -0500 Subject: [PATCH 1/2] Define extension event namespaces in v0.4 schema --- specification/v0.4/acceptance-criteria.md | 3 +++ .../examples/invalid/run-namespace-collision.json | 13 +++++++++++++ .../v0.4/examples/valid/run-extension-event.json | 13 +++++++++++++ specification/v0.4/schemas/common.schema.json | 10 ++++++++-- tests/test_v04_schema.py | 2 +- 5 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 specification/v0.4/examples/invalid/run-namespace-collision.json create mode 100644 specification/v0.4/examples/valid/run-extension-event.json diff --git a/specification/v0.4/acceptance-criteria.md b/specification/v0.4/acceptance-criteria.md index c0335f2..a8727da 100644 --- a/specification/v0.4/acceptance-criteria.md +++ b/specification/v0.4/acceptance-criteria.md @@ -6,6 +6,9 @@ - [x] Requests, Steps, Agents, runtime occurrences, evidence, Incidents, relationships, and semantic events are representable. - [x] Valid and invalid fixtures are automatically tested. - [x] Sensitive content is optional and extensibility is namespaced. +- [x] `event_name` accepts both the canonical `aiops.*` catalog and reverse-domain + namespaced extension events; extension names MUST NOT collide with the + `aiops` namespace. ## Review gates diff --git a/specification/v0.4/examples/invalid/run-namespace-collision.json b/specification/v0.4/examples/invalid/run-namespace-collision.json new file mode 100644 index 0000000..14bf163 --- /dev/null +++ b/specification/v0.4/examples/invalid/run-namespace-collision.json @@ -0,0 +1,13 @@ +{ + "spec_version": "0.4-draft", + "artifact_type": "run", + "id": "run-collision", + "started_at": "2026-07-21T06:00:00Z", + "status": "completed", + "requests": [], + "steps": [], + "relationships": [], + "events": [ + {"event_id": "event-1", "event_name": "aiops.custom.event", "occurred_at": "2026-07-21T06:00:00Z", "object_id": "run-collision", "object_type": "run"} + ] +} diff --git a/specification/v0.4/examples/valid/run-extension-event.json b/specification/v0.4/examples/valid/run-extension-event.json new file mode 100644 index 0000000..4d55445 --- /dev/null +++ b/specification/v0.4/examples/valid/run-extension-event.json @@ -0,0 +1,13 @@ +{ + "spec_version": "0.4-draft", + "artifact_type": "run", + "id": "run-ext-001", + "started_at": "2026-07-21T06:00:00Z", + "status": "completed", + "requests": [], + "steps": [], + "relationships": [], + "events": [ + {"event_id": "event-ext-1", "event_name": "io.deepagentlabs.agenticlens.custom_event", "occurred_at": "2026-07-21T06:00:00Z", "object_id": "run-ext-001", "object_type": "run"} + ] +} diff --git a/specification/v0.4/schemas/common.schema.json b/specification/v0.4/schemas/common.schema.json index 1d0ef50..4192365 100644 --- a/specification/v0.4/schemas/common.schema.json +++ b/specification/v0.4/schemas/common.schema.json @@ -4,7 +4,8 @@ "$defs": { "id": {"type": "string", "minLength": 1, "pattern": ".*\\S.*"}, "time": {"type": "string", "format": "date-time"}, - "extensions": {"type": "object", "propertyNames": {"pattern": "^[a-z0-9]+(?:[.-][a-z0-9]+)+$"}}, + "extension_name": {"type": "string", "pattern": "^(?!aiops(?:\\.|$))[a-z0-9]+(?:[_-][a-z0-9]+)*(?:\\.[a-z0-9]+(?:[_-][a-z0-9]+)*){2,}$"}, + "extensions": {"type": "object", "propertyNames": {"$ref": "#/$defs/extension_name"}}, "reference": { "type": "object", "required": ["id", "type"], @@ -33,11 +34,16 @@ "allOf": [{"if": {"properties": {"name": {"const": "cost"}}, "required": ["name"]}, "then": {"required": ["currency"]}}], "additionalProperties": false }, + "canonical_event_name": {"enum": ["aiops.run.started", "aiops.run.completed", "aiops.run.failed", "aiops.run.cancelled", "aiops.request.received", "aiops.request.completed", "aiops.request.rejected", "aiops.step.started", "aiops.step.completed", "aiops.step.failed", "aiops.step.cancelled", "aiops.agent.started", "aiops.agent.waiting", "aiops.agent.completed", "aiops.agent.failed", "aiops.model.requested", "aiops.model.responded", "aiops.model.failed", "aiops.prompt.rendered", "aiops.context.assembled", "aiops.tool.requested", "aiops.tool.authorized", "aiops.tool.completed", "aiops.tool.failed", "aiops.retrieval.started", "aiops.retrieval.completed", "aiops.retrieval.failed", "aiops.memory.read", "aiops.memory.written", "aiops.memory.updated", "aiops.memory.deleted", "aiops.memory.failed", "aiops.evaluation.completed", "aiops.evaluation.failed", "aiops.safety.detected", "aiops.safety.reviewed", "aiops.safety.mitigated", "aiops.reliability.detected", "aiops.reliability.recovered", "aiops.incident.opened", "aiops.incident.updated", "aiops.incident.mitigated", "aiops.incident.resolved"]}, "event": { "type": "object", "required": ["event_id", "event_name", "occurred_at", "object_id", "object_type"], "properties": { - "event_id": {"$ref": "#/$defs/id"}, "event_name": {"enum": ["aiops.run.started", "aiops.run.completed", "aiops.run.failed", "aiops.run.cancelled", "aiops.request.received", "aiops.request.completed", "aiops.request.rejected", "aiops.step.started", "aiops.step.completed", "aiops.step.failed", "aiops.step.cancelled", "aiops.agent.started", "aiops.agent.waiting", "aiops.agent.completed", "aiops.agent.failed", "aiops.model.requested", "aiops.model.responded", "aiops.model.failed", "aiops.prompt.rendered", "aiops.context.assembled", "aiops.tool.requested", "aiops.tool.authorized", "aiops.tool.completed", "aiops.tool.failed", "aiops.retrieval.started", "aiops.retrieval.completed", "aiops.retrieval.failed", "aiops.memory.read", "aiops.memory.written", "aiops.memory.updated", "aiops.memory.deleted", "aiops.memory.failed", "aiops.evaluation.completed", "aiops.evaluation.failed", "aiops.safety.detected", "aiops.safety.reviewed", "aiops.safety.mitigated", "aiops.reliability.detected", "aiops.reliability.recovered", "aiops.incident.opened", "aiops.incident.updated", "aiops.incident.mitigated", "aiops.incident.resolved"]}, + "event_id": {"$ref": "#/$defs/id"}, + "event_name": { + "description": "Either a canonical aiops.* name from the reviewed catalog, or a reverse-domain namespaced extension event (e.g. io.deepagentlabs.agenticlens.custom_event). Extension names MUST NOT start with the aiops namespace.", + "anyOf": [{"$ref": "#/$defs/canonical_event_name"}, {"$ref": "#/$defs/extension_name"}] + }, "occurred_at": {"$ref": "#/$defs/time"}, "object_id": {"$ref": "#/$defs/id"}, "object_type": {"enum": ["run", "request", "step", "agent", "model_interaction", "prompt", "context", "tool_invocation", "rag_retrieval", "memory_operation", "evaluation", "safety_signal", "reliability_event", "incident"]}, "attributes": {"type": "object"}, "extensions": {"$ref": "#/$defs/extensions"} }, diff --git a/tests/test_v04_schema.py b/tests/test_v04_schema.py index 741e134..0319a2e 100644 --- a/tests/test_v04_schema.py +++ b/tests/test_v04_schema.py @@ -138,7 +138,7 @@ def test_v04_schemas_are_valid() -> None: def test_v03_event_catalog_matches_v04_schema() -> None: conventions = (ROOT / "specification" / "v0.3" / "semantic-conventions.md").read_text(encoding="utf-8") documented = set(re.findall(r"`(aiops\.[a-z0-9.]+)`", conventions)) - schema_events = set(SCHEMA_DOCUMENTS["common.schema.json"]["$defs"]["event"]["properties"]["event_name"]["enum"]) + schema_events = set(SCHEMA_DOCUMENTS["common.schema.json"]["$defs"]["canonical_event_name"]["enum"]) assert documented == schema_events From dd1643bbd9143ab234ba18a1507f5a3548c554d1 Mon Sep 17 00:00:00 2001 From: PRAMOD B N Date: Sat, 8 Aug 2026 04:25:16 -0500 Subject: [PATCH 2/2] Clarify spec governance and draft tagging --- CONTRIBUTING.md | 20 ++++++++++++++++++++ README.md | 2 +- ROADMAP.md | 4 ++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1c34287..d86b960 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,3 +23,23 @@ Do not mark an acceptance gate complete without recorded evidence. External revi uv sync --extra dev uv run pytest ``` + +## Tagging draft snapshots and releases + +Snapshot repo state with **git tags**, not zip archives. GitHub already +generates a downloadable source zip/tarball for every tag or release, so +committing archives into the repo only adds undiffable bloat. + +- `specification/v0.4/conformance.md` asks implementers to cite claims like + *"aligned with v0.4-draft as observed on 2026-07-21"*. That citation is + only checkable if the repo state on that date is retrievable — that's + what a tag is for. +- Use `vX.Y-draft-YYYY-MM-DD` for an informal, citable snapshot of an + in-progress milestone (draft content keeps moving, so date-stamp it). +- Reserve the bare `vX.Y` tag for when a milestone's acceptance criteria + (see each milestone's `acceptance-criteria.md`) are fully checked and the + layer actually freezes — that tag then means something stable, not a + moving draft. +- Attach a GitHub Release on top of a tag once it's worth announcing + externally (e.g. summarizing which acceptance gates closed); not required + for every draft snapshot. diff --git a/README.md b/README.md index 21e7199..9304473 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ AI frameworks and instrumentation observability, evaluation, safety, and operations tools ``` -DeepAgentLabs stewards the specification. AgenticLens, Agentic Chaos, and DeepAgent MCP may implement or consume it, but none of them owns the contract. +DeepAgentLabs stewards the specification today and is its sole editor. AgenticLens, Agentic Chaos, and DeepAgent MCP may implement or consume it, but none of them owns the contract. Vendor-neutrality is the design goal, not yet an established fact: several acceptance gates — independent implementer review, validation against artifacts from at least two unrelated producers — remain open (see each milestone's acceptance criteria and the [roadmap](ROADMAP.md)). Treat "vendor-neutral" as the intended end state until those gates close. ## Current maturity diff --git a/ROADMAP.md b/ROADMAP.md index 04a64e1..b827413 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -119,6 +119,10 @@ Formalize concepts proven in implementation repositories. - optional report/investigation artifact schemas (if implementation usage proves the need) - incident context and operator-facing summary semantics +- OpenTelemetry GenAI semantic convention binding — a non-normative mapping + document from canonical `aiops.*` events and common attributes to OTel + spans, span events, and resource attributes, so producers already emitting + OTel do not need to invent their own bridge independently Success means implementations can attach provenance to findings using spec-standard objects, and producers can run conformance checks independently.