Skip to content

Releases: aiperceivable/apcore

Release 0.21.0 (2026-05-06)

07 May 01:57

Choose a tag to compare

Added

  • §2.5 Reserved Words — ephemeral added to framework reserved list (RFC rfc-ephemeral-modules.md accepted). New reserved namespace ephemeral.* for programmatically-generated runtime modules synthesized by LLM agents (à la ToolMaker, ACL 2025). Standard Registry.register() only — register_internal() MUST reject ephemeral.* IDs. Reserved-namespace semantics table added below the YAML block. See docs/spec/rfc-ephemeral-modules.md for the full namespace contract (registration / lifecycle / audit / sandboxing).
  • §4.4 ModuleAnnotations — new discoverable: boolean field (default true). Controls visibility in enumeration surfaces (Registry.list(), Registry.find(), manifest export, MCP tools/list). false hides the module from discovery while keeping it callable by exact ID. ephemeral.* modules SHOULD set discoverable: false.
  • §5.6 Module Interface Protocol — optional preview() method (RFC rfc-preview-method.md accepted). Modules implement preview(inputs, context) -> PreviewResult | null to self-report structured-diff predictions of state changes the call would produce. Sits alongside preflight() (warnings) — they are orthogonal surfaces. Exception semantics mirror preflight() (advisory warning via module_preview check entry; does not fail validation). Pseudocode interface block + optional_methods YAML both updated.
  • §12.8 PreflightResult schema — new predicted_changes: List<Change> field; Change and PreviewResult types defined. Change has required action / target / summary (free-form strings) and optional before / after snapshots; x-* extension fields are permitted (cross-SDK encoding patterns documented in the RFC). PreflightCheckResult.check enum extended with module_preview.
  • §4.6 conventions table — three new x-* AI-routing keys (D-57). Documentation-only registration of three metadata conventions surfaced by the 2025–2026 LLM-agent / tool-use frontier-research alignment audit:
    • x-reasoning-demand (low | medium | high) — hint of the minimum reasoning capability the calling agent needs; consumed by upstream model routers for tier selection. Aligns with RouteLLM (ICLR 2025), xRouter (arXiv 2510.08439), and Cost-Aware Model Orchestration (arXiv 2512.01099).
    • x-required-context-keys — array of context.data key names the module reads, enabling orchestrators to inject required state ahead of the call. Does not include framework-owned Context fields (trace_id, caller_id, etc.).
    • x-supports-dry-run (boolean) — module-level signal that Executor.validate() (§12.2) is meaningful for this module.
  • docs/spec/2026-05-decision-log.md — D-57 (§4.6 reasoning/context/dry-run conventions) — marked resolved. Resolution status block updated to include D-57.

Notes

  • No SDK behavior change for §4.6 D-57 conventions. All three SDKs treat module metadata as a free-form dict / Record<string, unknown> / serde_json::Value; the framework explicitly does not validate metadata content (§4.6 "Metadata Design Principles"). New x-* keys are additive conventions only.
  • Strict-mode export unaffected by D-57. §4.16 mandates that to_strict_schema() strips all x-* extension fields, so the new keys do not surface in strict-mode output.
  • SDK rollout for §2.5 / §4.4 / §5.6 / §12.8 spec promotions is synchronized. All three SDKs ship the full v0.21.0 surface (Stage 2 Module.preview() + Stage 3 ephemeral.* namespace + discoverable annotation + audit single-emit + register_internal() rejection):
    • apcore-python v0.21.0 — pyproject.toml bumped; PR #26 + iter-11 alignment shipped Stage 3; commit 203a9a6 shipped Stage 2.
    • apcore-typescript v0.21.0 — package.json bumped; PR #29 + iter-11 shipped Stage 2 (with TypeBox Type.Unsafe form for Change.x-*); commit 577b09b shipped Stage 3.
    • apcore-rust v0.21.0 — Cargo.toml bumped; PR #25 shipped Stage 2 prerequisite (#[non_exhaustive] hygiene); commits afb6e05 + e6abb7b shipped Stage 2 Module::preview() + Stage 3 ephemeral/discoverable.
  • Conformance fixture annotations_extra_round_trip.json deferred. Per rfc-ephemeral-modules.md "Transitional fixture handling during multi-SDK rollout", the fixture is NOT updated to require discoverable until all 3 SDKs have shipped support. SDKs implementing discoverable MAY make their conformance test runner pilot-tolerant in the interim. Synchronized fixture update will land in a follow-up PR after TypeScript and Rust ship discoverable.

Release 0.20.0

05 May 13:17

Choose a tag to compare

[0.20.0] - 2026-05-05

Added

  • UsageExporter Protocol/interface/trait + NoopUsageExporter + PeriodicUsageExporter in all 3 SDKs (#45 §3, D-55). Push-style usage summary export distinct from pull-style PrometheusExporter. PeriodicUsageExporter polls UsageCollector.summary() every interval_seconds (default 3600 = 1 hour) and calls exporter.export(summary). stop() halts the loop, awaits exporter.shutdown(), and is idempotent. apcore SDKs do not ship transport-bound exporters (HTTP, Kafka, etc.) — those are explicitly out-of-tree. Documented in docs/features/observability.md "## UsageExporter (push-style)". Conformance: conformance/fixtures/usage_exporter.json (3 cases).
  • TypeScript registry _filterIdConflicts 8-stage decomposition matches Rust + Python (D-32, D-56). TypeScript _discoverDefault refactored to expose _filterIdConflicts as a separate private helper between candidate enumeration and registration; _registerInOrder reduced to pure registration. Cross-language conformance no longer special-cases TS — all 3 SDKs follow the canonical 8-stage Algorithm A04 shape.
  • conformance/fixtures/usage_exporter.json (#45 §3, D-55) — 3 cross-language test cases: NoopUsageExporter no-op, PeriodicUsageExporter pushes summary at interval, stop() is idempotent and drains in-flight exports.
  • conformance/fixtures/sensitive_keys_default.json (#43 §5, D-54) — 4 cross-language test cases: canonical 16-entry default list shape, legacy _secret_* prefix redaction under default, common credential-term redaction (case-insensitive substring), operator override replaces (does not merge) the default.
  • docs/spec/2026-05-decision-log.md## D-54 — sensitive_keys canonical default list, ## D-55 — UsageExporter push interface (#45 §3), ## D-56 — TS _discoverDefault 8-stage refactor — all marked resolved. Resolution status block updated to reflect D-30, D-31, D-32, D-54, D-55, D-56 as resolved.
  • docs/features/async-tasks.mdContract: ReaperHandle.stop block (audit N-001) — Normative cross-language declaration that ReaperHandle.stop() MUST be async in all three SDKs (async def in Python, Promise<void> in TypeScript, async fn in Rust) with drain semantics — cancel + await termination — and idempotent: true.
  • conformance/fixtures/trace_context.json (#35) — 8 cross-language test cases for the TraceContext W3C alignment: ordered tracestate roundtrip, 32-entry cap, malformed-entry tolerance, case-insensitive Traceparent/TRACESTATE header lookup, dynamic trace_flags honoring on extract→inject, accepted parent_id override (^[0-9a-f]{16}$), and INVALID_PARENT_ID rejection of malformed overrides.
  • docs/features/event-system.md — Event Naming Convention section (#36) — Normative apcore.<subsystem>.<event> form for framework-emitted events, glob-subscription examples (apcore.registry.* / apcore.health.*) across Python/TypeScript/Rust, and a deprecation table mapping legacy names (module_registered, module_unregistered, apcore.error.threshold_exceeded, apcore.latency.threshold_exceeded) to their canonical replacements with v0.22.0 removal target. Adds a "Configuration-driven subscribers" section listing all five built-in factories (webhook, a2a, file, stdout, filter) with a multi-subscriber YAML example.
  • docs/features/system-modules.md — Contextual Auditing subsection (#45.2) — Normative rule that control modules (update_config, toggle_feature, reload_module) MUST include caller_id and (when present) a redacted identity snapshot in their emitted audit events; caller_id defaults to the literal string "@external" when unauthenticated; x-sensitive Identity fields are replaced with "<redacted>". Cross-language Python/TypeScript/Rust examples of the audit event payload shape.
  • Public SubscriberFactory API in Python SDK (parity with TS+Rust) (#36).
  • conformance/fixtures/event_naming.json (#36 / D-34) — 8 cross-language test cases: canonical apcore.registry.module_registered / apcore.registry.module_unregistered, dual-emit of legacy names with deprecated:true during v0.21.x, glob subscription matching for apcore.registry.* and apcore.health.*, canonical apcore.health.error_threshold_exceeded / apcore.health.latency_threshold_exceeded, and cross-subsystem glob isolation.
  • conformance/fixtures/contextual_audit.json (#45.2 / D-35) — 7 cross-language test cases: caller_id propagation in apcore.config.updated, @external default for null/empty caller_id, redacted identity snapshot inclusion for apcore.module.toggled, x-sensitive field redaction (e.g., bearer_token<redacted>), caller_id + identity in apcore.module.reloaded, and audit event emission even when no AuditStore is configured.
  • docs/spec/2026-05-decision-log.md D-34 (event naming canonicalization) and D-35 (contextual auditing for control plane) — both marked resolved with action: rename + dual-emit during v0.21.x for D-34; payload extension for D-35.
  • Pipeline StepMiddleware extension point in all 3 SDKs (#33). Lifecycle-shaped API (before_step / after_step / on_step_error) mirroring module-level Middleware — onion ordering, first-recovery-wins on errors, async support across Python/TypeScript/Rust. Documented in docs/features/middleware-system.md "Pipeline Step Middleware (Issue #33)" with three contract blocks. Conformance: conformance/fixtures/pipeline_step_middleware.json (6 cases).
  • Python BatchSpanProcessor for non-blocking span export (#43, parity with TS+Rust). Cross-SDK parity contract — identical default tunables (max_queue_size=2048, max_export_batch_size=512, schedule_delay_ms=5000, export_timeout_ms=30000), identical on_end / force_flush / shutdown lifecycle, identical drop-on-full-queue semantics. Documented in docs/features/observability.md "Batch span processing" section.
  • docs/spec/2026-05-decision-log.md — D-36 (Pipeline StepMiddleware), D-37 (Pipeline configuration fail-fast), D-38 (BatchSpanProcessor cross-SDK parity), all resolved.
  • StorageBackend trait/interface in all 3 SDKs with InMemoryStorageBackend default; ErrorHistory, UsageCollector, MetricsCollector accept injected backend (#43).
  • OverridesStore and FileOverridesStore in TypeScript SDK (parity with Python+Rust) (#45.1).
  • Registry.discover_multi_class / Registry.discoverMultiClass method in Python+TS (D-15).
  • docs/features/observability.md## Pluggable storage backends and ## ErrorHistory eviction performance subsections documenting the cross-SDK StorageBackend surface, InMemoryStorageBackend default, out-of-tree policy for Redis/Postgres/S3, and the lazy-deletion semantics of the O(log N) min-heap eviction.
  • docs/features/system-modules.md## Persistent Overrides — pluggable OverridesStore subsection covering OverridesStore parity across all 3 SDKs, with cross-language FileOverridesStore wiring during APCore construction and the missing-path-on-first-run guarantee.
  • docs/features/multi-module-discovery.md — Updated Registry.discover_multi_class Contract block to explicitly document that all 3 SDKs expose the discovery routine as a method on Registry; added a per-SDK method/internal-helper mapping table and cross-language usage examples (D-15).
  • docs/features/async-tasks.md — Notes documenting the Python TaskStore.put → save rename + deprecation alias (D-10), the Python TaskInfo.attempt_number → retry_count rename + deprecation property (D-13), removal of Python's TaskStatus.RETRYING (D-12), and the Rust RetryConfig::default().max_retries: 3 → 0 alignment (D-14).
  • docs/spec/2026-05-decision-log.md## Resolution status — 2026-05-03 addendum marking D-10, D-12, D-13, D-14, D-15, D-19, D-25, D-27, and D-28 resolved; added new entries ## D-39 — StorageBackend cross-SDK abstraction (resolved) and ## D-40 — TS overrides persistence parity (resolved).
  • conformance/fixtures/storage_backend.json — 5 cross-language test cases covering StorageBackend save+get round-trip, list-with-prefix filtering, idempotent delete, namespace isolation, and save-overwrites semantics.
  • conformance/fixtures/overrides_store.json — 5 cross-language test cases covering OverridesStore: save persists across reopen, startup applies overrides after base config, in-memory store for tests, missing path on first run is OK, delete idempotency.
  • Granular reload via path_filter input in ReloadModule across all 3 SDKs (#45.4).
  • Rust Config::reload_from_disk() for refreshing static config without binary restart (#45.5).
  • Error fingerprinting in ErrorHistory across all 3 SDKs — dedup by (error_code, top-frame hash, sanitized message template) instead of exact message (#43 §4).
  • Configurable redaction via obs.redaction.regex_patterns and obs.redaction.sensitive_keys Config keys (#43 §5).

Changed

  • Default obs.redaction.sensitive_keys redaction list expanded to canonical 16-entry superset across all 3 SDKs (#43 §5, D-54). Default now ships as ["_secret_*", "password", "passwd", "secret", "token", "api_key", "apikey", "apiKey", "access_key", "private_key", "authorization", "auth", "credential", "cookie", "session", "bearer"]. The leading _secret_* glob preserves the legacy _secret_-prefix behavior under the canonical default; the redundant apiKey/apikey pair is intentional so cross-SDK fixtures byte-match. Operator overrides via obs.redaction.sensitive_keys in apcore.yaml replace (do not merge with) the default. Documented in docs/features/observability.md "## Canonical default sensitive_keys".
  • Trace context (#35) — docs/features/observability.md W3C Trace Context section adds tracestate propagation (ordered, 32-entry cap, malformed-entry tolerance), case-insensitive heade...
Read more

Release 0.19.0 (2026-04-19)

19 Apr 09:38

Choose a tag to compare

Changed

  • PROTOCOL_SPEC §5.7 — trace_id format pattern tightened from format: uuid (ambiguous: dashed vs hex) to pattern: "^[0-9a-f]{32}$" (32-char lowercase hex, W3C Trace Context compatible). Resolves internal spec contradiction between §5.7 (format: uuid), §10.5 example (dashed UUID), and §10.5 traceparent_header (hex without dashes).
  • PROTOCOL_SPEC §10.5 — Trace ID Format section rewritten to align with W3C Trace Context Level 2. Adds explicit external_trace_parent_handling rules: strict 32-hex validation only; all-zero and all-f rejected per W3C; no auto-normalization (dashed UUID stripping, case folding) at Context.create — pushed to TraceParent parser or user's ContextFactory. Implementations MUST regenerate + log WARN on invalid input; MUST NOT raise.

Added

  • PROTOCOL_SPEC §5.15.2 — DEPENDENCY_VERSION_MISMATCH error code (new, non-retryable). Raised when a module in dependencies.requires exists but its registered version does not satisfy the declared version constraint. For dependencies.optional the same situation logs WARN and skips the dependency edge.
  • conformance/fixtures/dependency_version_constraints.json — 15 cross-SDK test cases covering exact match, >=/<=, range (>=1.0.0,<2.0.0), caret (^1.2.3, including ^0.2.3 major-zero semantics), tilde (~1.2.3), partial-version shortcuts ("1" matches 1.x.x), no-constraint accepts any, and optional-dependency skip-on-mismatch.
  • PROTOCOL_SPEC §5.7 — Note on external correlation IDs. Documents that existing projects' request/correlation identifiers (X-Request-ID, ULID, AWS X-Ray, etc.) SHOULD be preserved in context.data["x-correlation-id"] alongside trace_id, not used to overwrite it. Establishes the dual-ID model at the spec level.
  • PROTOCOL_SPEC §10.5 — Forward-compatibility Note. Non-normative acknowledgment that trace_id format is a versioned contract, not a permanent guarantee. Future protocol versions MAY introduce alternative formats or structured trace IDs for multi-agent or non-linear trace topologies.
  • docs/guides/integrating-existing-projects.md — New user guide covering Django, Express, and Actix integration patterns for projects already carrying their own request-ID / correlation-ID system.
  • conformance/fixtures/context_trace_parent.json — Cross-language fixture with 10 test cases covering valid 32-hex, dashed UUID rejection, uppercase rejection, W3C-invalid all-zero/all-f rejection, length errors, non-hex characters, empty string, and the no-trace_parent baseline.
  • docs/spec/DECLARATIVE_CONFIG_SPEC.md v1.0 — New unified specification for declarative YAML configuration across all three SDKs. Covers bindings YAML (§3), pipeline config (§4), entry-point meta (§5), auto_schema semantics (§6), canonical error model with exact message templates (§7), configurable policy limits (§9). Establishes core principles: YAML syntax 100% consistent across SDKs; never silently drop fields; auto-processing as default; JSON Schema for structure, apcore.yaml for policy.
  • schemas/binding.schema.json updates — Relaxed target regex to support TypeScript ESM specifiers (./relative, @scope/pkg) and Rust handler-map keys. auto_schema field now accepts boolean or "true" / "permissive" / "strict" enum. Schema mode mutex rules rewritten from oneOf to allOf + if/then (supports implicit auto default when no mode specified). DisplayOverlay changed from additionalProperties: false to propertyNames pattern + additionalProperties: SurfaceOverride for future surface extensibility. Annotations expanded from 5 to 12 fields (added streaming, cacheable, cache_ttl, cache_key_fields, paginated, pagination_style, extra) to align with module-meta.schema.json. version field pattern moved to configurable policy (version_require_semver). Added spec_version top-level field.
  • schemas/apcore-config.schema.jsonpipeline and validation sections — New PipelineConfig definition with remove, configure, steps structure; PipelineStep with type/handler mutual exclusion, after/before positioning, and metadata fields (match_modules, ignore_errors, pure, timeout_ms). New ValidationConfig with configurable policy limits for bindings (description_max_length, documentation_max_length, tags_pattern, version_require_semver) and pipeline (step_name_max_length, timeout_ms_max).
  • conformance/fixtures/binding_yaml_canonical.yaml — Cross-SDK binding YAML conformance fixture with 3 entries testing explicit auto_schema (permissive), explicit input/output schemas with display overlay, and auto_schema strict mode. All three SDKs must parse this fixture identically.
  • conformance/fixtures/binding_errors.json — 6 canonical error message test cases for cross-SDK byte-for-byte message parity (BindingFileInvalidError, BindingSchemaModeConflictError, BindingSchemaInferenceFailedError, PipelineHandlerNotSupportedError, BindingInvalidTargetError, BindingModuleNotFoundError).

Fixed

  • PROTOCOL_SPEC §8 Error Code Registry — Added missing DEPENDENCY_VERSION_MISMATCH entry alongside DEPENDENCY_NOT_FOUND. Previously the behavior was implied by §5.3 version constraint syntax (^, ~, ranges) without a corresponding error code in §8, leaving SDKs without a normative failure mode.
  • SDK compliance with §5.15.2 DEPENDENCY_NOT_FOUND — All three SDKs (apcore-python, apcore-typescript, apcore-rust) now raise the spec-mandated DEPENDENCY_NOT_FOUND error code for missing required dependencies. Previously all three raised MODULE_LOAD_ERROR, silently diverging from the spec.
  • SDK CircularDependencyError.details.cycle_path parity — Rust SDK now carries cycle_path as structured details, matching Python (details["cycle_path"]) and TypeScript (details.cyclePath). Previously Rust only placed the path in the message string, forcing downstream consumers to parse it.

Deprecated

  • The pre-existing MUST NOT allow externally provided unvalidated trace_id rule in §10.5 is superseded by the explicit validation/normalization pipeline — "unvalidated" is now impossible because every input is either accepted verbatim or replaced with a fresh trace_id.

Release 0.18.0 (2026-04-15)

15 Apr 09:15

Choose a tag to compare

Breaking changes in this release. See MIGRATION-v0.18.md for the consolidated migration guide covering all four repositories.

Added

  • APCore constructor simplified — removed config_path parameter; use Config.load() instead (e.g. APCore(config=Config.load("apcore.yaml"))). This applies to all SDKs: Python, TypeScript, and Rust. The explicit two-step pattern keeps the constructor focused and avoids mutual-exclusivity validation.
  • System module JSON Schemas — 6 new output schemas in schemas/: sys-control-reload-module, sys-control-toggle-feature, sys-control-update-config, sys-health-module, sys-health-summary, sys-manifest-full. Each declares $schema, $id, additionalProperties: false, and descriptions on every property.
  • Conformance README coverage gap table — Documents 6 algorithms (A01, A07, A12, A21, A22, A23) that lack conformance fixtures.
  • Conformance README non-standard patterns section — Documents sub_cases and forbidden_root_keys test patterns for SDK implementers.
  • PROTOCOL_SPEC §2.7 — canonical_id maximum length raised from 128 to 192 characters. Motivated by deep-namespace languages (Java/.NET/Spring FQN-derived IDs) where snake_case-converted fully-qualified names can exceed 128 in edge cases. 192 is filesystem-safe (192 + ".binding.yaml" = 205 bytes < 255-byte filename limit on ext4/xfs/NTFS/APFS/btrfs) and remains within VARCHAR(255) for typical persistence layers. MCP alias 64-char hard limit (OpenAI function name spec) is unchanged and still requires alias mapping for any module_id > 64. Schemas updated: binding.schema.json, module-schema.schema.json, module-meta.schema.json declare module_id.maxLength: 192; acl-config.schema.json callers/targets pattern strings raised to 192 to remain symmetric. Algorithm A01 (directory_to_canonical_id) Step 6 / 7 length threshold updated to 192. Conformance test T01-006 boundary updated to >192 chars. Forward-compatible relaxation: producers targeting mixed-version ecosystems should keep IDs ≤ 128 until all consumers are upgraded.
  • PROTOCOL_SPEC §5.6 yaml block now declares required_attributes: (input_schema, output_schema, description) explicitly. The pseudocode block already marked these as "Required definitions" but the yaml block beneath only listed required_methods and optional_attributes, so a reader of the yaml alone could not see the attribute requirement. Closes a sync audit contradiction.
  • PROTOCOL_SPEC §4.4.1 — Annotations Extension Field (extra) Wire Format — New normative section defining the canonical on-the-wire shape of ModuleAnnotations.extra. Producers MUST serialize as a nested {"extra": {...}} object and MUST NOT flatten extension keys to the annotations root. Consumers MUST accept the nested form; legacy top-level overflow keys MAY be tolerated for one MINOR cycle. When both forms appear in the same input, the nested value wins.
  • extra field in Annotations schemaschemas/module-meta.schema.json now declares extra as an object with additionalProperties: true. The outer Annotations object retains additionalProperties: false, so unknown root-level keys are no longer silently accepted at the schema layer.
  • conformance/fixtures/annotations_extra_round_trip.json — 8 cross-language test cases locking the wire format: canonical nested round-trip, empty extra, namespaced keys, Unicode and nested object values, legacy flattened deserialization tolerance, nested-wins precedence, forbidden-root-keys negative case, and dotted-keys-are-not-paths.
  • MIGRATION-v0.18.md — Consolidated migration guide covering all four breaking changes shipped in this release (annotations wire format, apcore-rust Config restructure, apcore-python event alias removal, misc cleanup).
  • 8 new feature specification docs. The following features were implemented in both apcore-python and apcore-typescript SDKs but had no corresponding feature spec in the protocol repo:
    • docs/features/error-system.md — Structured error hierarchy (30+ error types), error codes, AI guidance fields (retryable, ai_guidance, user_fixable, suggestion), ErrorCodeRegistry for custom module error codes.
    • docs/features/extension-system.mdExtensionManager with 6 built-in extension points (discoverer, middleware, acl, span_exporter, module_validator, approval_handler), plugin wiring via apply().
    • docs/features/call-chain-guard.md — Algorithm A20: call depth limiting, circular call detection, frequency throttling with configurable thresholds.
    • docs/features/cancellation.mdCancelToken cooperative cancellation, executor timeout integration with 5-second grace period.
    • docs/features/async-tasks.mdAsyncTaskManager for background module execution with concurrency semaphore, task lifecycle tracking, and cleanup.
    • docs/features/streaming.md — Three-phase streaming pipeline (setup → chunk emission → post-validation), deep merge with depth cap.
    • docs/features/identity-system.mdIdentity data structure with well-known types (user, service, ai, system, anonymous), ContextFactory protocol for web framework integration.
    • docs/features/apcore-client.mdAPCore unified client feature spec covering initialization modes, auto-registration behavior, and method summary.
  • mkdocs.yml navigation updated. Feature Specifications section expanded from 11 to 19 entries (alphabetically sorted).
  • README.md Documentation Index updated. Added all 8 new feature docs to the Feature Specifications table.

Fixed

  • PROTOCOL_SPEC §10.8 — Span attribute "caller" corrected to "caller_id". The span naming convention section listed "caller" as a SHOULD attribute, inconsistent with the caller_id field name used everywhere else in the specification (§2.1, §6, §7, Context object). All SDKs already used caller_id in their span implementations.
  • PROTOCOL_SPEC §9.3 — RFC 2119 keyword compliance. Five constraint validation statements in the A12_validate_config pseudocode used lowercase must instead of uppercase MUST. Corrected to match RFC 2119 normative intent.
  • mkdocs.yml navigation — 4 orphaned docs now reachable. Added api/client-api.md, features/config-bus.md, features/event-system.md, and features/system-modules.md to the site navigation. These pages existed and were referenced in README.md but were not in the MkDocs nav tree.
  • JSON Schema property descriptions. Added missing description fields to 4 properties in module-schema.schema.json (ErrorSchemaObject.type, .properties, .required, and the description property definition) and 3 surface-override objects in binding.schema.json (cli, mcp, a2a). All properties now comply with the "every property must have a description" rule.
  • docs/features/streaming.md — Step count corrected from "Steps 1–6" to "Steps 1–7". The text listed 7 pipeline phases (Context Creation through Input Validation) but labelled them "Steps 1–6". PROTOCOL_SPEC §6574 explicitly states "Steps 1–7 identical to call()" for stream().
  • docs/api/executor-api.mdvalidate() step count corrected. Previously said "Steps 1-7"; now says "Steps 1-6, plus optional module-level preflight" to match PROTOCOL_SPEC §12.8.
  • docs/spec/conformance.md T11-001 — Deprecated execute_async() replaced with call_async(). The execute_async() method was removed in v0.10; conformance table still referenced the old name.
  • docs/guides/creating-modules.md — Rust examples added. Two tabbed code sections (module definition and module usage) only had Python and TypeScript examples. Added Rust tabs with complete, importable examples using apcore::{Module, Context, Registry, Executor}.
  • Cross-language extra serialization divergence — Audit revealed that apcore-rust ≤ 0.17.1 used #[serde(flatten)] and emitted extension keys at the annotations root, while apcore-python and apcore-typescript emitted nested extra objects. A binding round-tripped through Rust would silently lose the extra payload (the nested object collapsed into extra["extra"]). All three SDKs are now aligned on the nested form per §4.4.1.
  • Python/TypeScript precedence inversion — Both SDKs previously merged top-level overflow over explicit nested extra ({**explicit, **overflow}), making nested values losable. Per §4.4.1 rule 7, nested now wins. Behavior change is observable only when the same key appears in both forms in the same input — a pathological case that no conformant producer emits.
  • apcore-rust Config no longer silently ignored spec-conformant YAML. The struct previously declared executor and observability fields at the root of Config instead of nested under executor and observability namespaces, contradicting PROTOCOL_SPEC §9.1 and the Python/TypeScript SDKs. Loading a YAML file that used the canonical nested form would cause typed fields to remain at default values while the user data ended up in an unused settings HashMap entry. v0.18.0 restructures apcore-rust Config to a nested form, drops the legacy short field names, and rejects v0.17.x-style YAML with a hard error pointing at MIGRATION-v0.18.md. See apcore-rust/CHANGELOG.md for the full type-by-type rename table.
  • docs/spec/design-context-annotations-acl.md no longer contradicts shipped spec. The historical design document still claimed "ModuleAnnotations is frozen with 11 fields" and recommended #[serde(flatten)] for the Rust extra field. A superseded banner now points readers at PROTOCOL_SPEC §4.4.1 for current normative behavior; the original text is preserved for historical context.
  • mkdocs.yml Home nav now points at README.md (which exists) instead of index.md (which never did), eliminating a noisy mkdocs build warning.
  • **PROTOCOL_SPEC §2.1 — Alg...
Read more

v0.17.1

15 Apr 08:43

Choose a tag to compare

[0.17.1] - 2026-04-06

Added

  • minimal strategy preset — 4-step pipeline (context_creationmodule_lookupexecutereturn_result) for pre-validated internal hot paths. Documented in all three SDKs and spec.
  • Core vs Optional steps overview — New §4.0 in design-execution-pipeline.md with ASCII diagram showing which 4 steps are mandatory and which 7 are removable.
  • Middleware vs Custom Step selection guide — Decision matrix in design-execution-pipeline.md §4.2 and practical guide with cross-language examples in docs/guides/middleware.md §11.
  • requires / provides step dependency metadata — Optional advisory fields on BaseStep (Python), Step interface (TypeScript), and Step trait (Rust). ExecutionStrategy warns at construction and insertion time if a step's requires are not satisfied by preceding steps' provides.
  • Execute step replacement warning!!! warning admonition in design-execution-pipeline.md explaining risks of replacing the execute step.
  • Strategy summary table — All preset strategies documented with step counts, removed steps, and use cases.

Fixed

  • PROTOCOL_SPEC.md pipeline order — Steps 6/7 swapped to match all SDK implementations (middleware_beforeinput_validation). Step 2 renamed from "Safety Checks" to "Call Chain Guard".
  • design-execution-pipeline.md alignment — Step inventory table, code examples, JSON pipeline example, and strategy references updated for correct stage order, naming, and validate_only removal.
  • validate_only strategy removed from spec — Never implemented in any SDK; validate() method with dry_run=True provides the same behavior more cleanly.

v0.17.0

15 Apr 08:42

Choose a tag to compare

[0.17.0] - 2026-04-04

Added

Pipeline v2 — Declarative Step Metadata

  • 4 new BaseStep fieldsmatch_modules (glob patterns for selective step execution), ignore_errors (fault-tolerant continuation on step failure), pure (no side effects, safe for dry-run/validate mode), timeout_ms (per-step timeout in milliseconds). Implemented across all three SDKs (Python, TypeScript, Rust).
  • PipelineContext.dry_run — When true, PipelineEngine skips steps with pure=false, enabling validate() to run user-defined pure steps automatically.
  • PipelineContext.version_hint — Passed through to module_lookup for version negotiation.
  • PipelineContext.executed_middlewares — Tracks which middleware ran for on_error recovery chain.
  • StepTrace.skip_reason — Records why a step was skipped: "no_match", "dry_run", or "error_ignored".
  • YAML pipeline configuration (Python) — pipeline section in apcore.yaml with remove, configure, and steps directives. Step resolution via type (registry) and handler (import path).

Changed

Pipeline Step Rename

  • safety_checkcall_chain_guard — Renamed across all SDKs to accurately describe the step's purpose (call chain depth/cycle/repeat checks, not transport-level rate limiting).
  • TypeScript builtin. prefix removed — All built-in step names in the TypeScript SDK dropped the builtin. prefix for cross-SDK consistency (e.g., builtin.context_creationcontext_creation).

Pipeline Step Order

  • Steps 6 and 7 swappedmiddleware_before now executes before input_validation (was the reverse). Middleware transforms are now validated by the subsequent input_validation step, aligning with the Kubernetes Mutating → Validating admission order.

Fixed

  • Middleware transforms now validated — Previously, middleware modifications to inputs were either never re-validated (production code) or silently discarded (pipeline abstraction). The step order swap ensures transformed inputs pass schema validation.

Release 0.15.1

05 Apr 03:28

Choose a tag to compare

Changed

  • Env prefix convention simplified — Removed the ^APCORE_[A-Z0-9] reservation rule from namespace registration. Sub-packages now use single-underscore prefixes (APCORE_MCP, APCORE_OBSERVABILITY, APCORE_SYS) instead of the double-underscore form. The longest-prefix-match dispatch algorithm already disambiguates correctly; the previous restriction was unnecessary.
  • Built-in namespace env prefixes: APCORE__OBSERVABILITYAPCORE_OBSERVABILITY, APCORE__SYSAPCORE_SYS.

Release 0.15.0

05 Apr 03:27

Choose a tag to compare

Added

Protocol Specification (v1.6.0-draft)

  • Config Bus Architecture (§9.4) — apcore.Config upgraded from internal configuration tool to ecosystem-level Config Bus. Any package (apcore ecosystem or third-party) can register a namespace with optional JSON Schema validation, environment variable prefix, and defaults. Design principles: bus not center, zero-cost adoption, gradual integration, cross-language consistency, strict/flexible coexistence
  • Namespace Registration (§9.5)Config.register_namespace(name, schema, env_prefix, defaults) API with cross-language examples (Python, TypeScript, Rust, Go, Java). Global (class-level) registry shared across Config instances. Late registration permitted with explicit reload() to apply. No unregister_namespace in this version
  • Unified Configuration File (§9.6) — Single YAML file with namespace-partitioned sections. Automatic mode detection: legacy mode (no apcore: key, fully backward compatible) vs namespace mode (apcore: key present). _config reserved namespace for meta-configuration (strict, allow_unknown)
  • Mount Mechanism (§9.7)config.mount(namespace, from_file|from_dict) for attaching external configuration sources without requiring a unified file. Primary integration path for third-party projects with existing config systems
  • Per-Namespace Env Override (§9.8) — Each namespace declares its own env_prefix. Longest-prefix-match dispatch algorithm resolves ambiguity. APCORE_MCP double-underscore convention for apcore sub-packages to avoid collision with APCORE_ prefix. Compatibility note for apflow's simpler env convention
  • Namespace-Aware Access API (§9.9)config.get("namespace.key.path") with dot-path namespace resolution algorithm. config.namespace(name) for full subtree retrieval. config.bind(ns, type) / config.get_typed(path, type) for typed access. Config.registered_namespaces() for introspection
  • Validation Algorithm A12-NS (§9.10) — Extended A12 for namespace mode: validates apcore namespace with original algorithm, validates registered namespaces against their JSON Schema, handles unknown namespaces per strict/allow_unknown settings
  • Hot-Reload Namespace Support (§9.11)config.reload() re-reads YAML, re-detects mode, re-applies namespace defaults and env overrides, re-validates, and re-reads mounted files
  • Cross-Language Implementation Requirements (§9.12) — MUST/SHOULD API surface table, language-idiomatic naming matrix, thread safety requirements, parameter passing style note
  • Ecosystem Integration Patterns (§9.13) — Convention table for all apcore packages (namespace, env prefix, schema file). Third-party defensive integration pattern. Framework auto-registration examples (Django AppConfig.ready(), FastAPI module-level, NestJS)
  • Config Discovery (§9.14) — Optional (MAY) automatic config file discovery with search order: $APCORE_CONFIG_FILE./project.yaml./apcore.yaml → user-level config
  • New error codesCONFIG_NAMESPACE_DUPLICATE, CONFIG_NAMESPACE_RESERVED, CONFIG_ENV_PREFIX_CONFLICT, CONFIG_MOUNT_ERROR, CONFIG_BIND_ERROR

Cross-Package Consistency (§8.8, §9.15, §9.16)

Three mechanisms addressing ecosystem consistency across apcore, apcore-mcp, apcore-cli, apcore-a2a and third-party packages:

  • Error Formatter Registry (§8.8) — Shared ErrorFormatter protocol and registration point. apcore-mcp and apcore-a2a each independently implement protocol-specific error mappers (MCP camelCase/sanitization, A2A JSON-RPC code mapping); this registry makes the contract explicit and discoverable. Adoption is SHOULD-level for ecosystem adapters — apcore does not ship adapter-specific formatters. New error code: ERROR_FORMATTER_DUPLICATE

  • apcore Built-in Namespace Registrations (§9.15) — The framework pre-registers two namespaces for its own subsystems, applying the Config Bus pattern to apcore's own internal configuration. Both promote existing flat keys already present in apcore-python's config.py; migration is 1:1 with no breaking changes:

    • observability (APCORE_OBSERVABILITY) — Extracts apcore.observability.* flat keys (tracing, metrics, logging, error_history, platform_notify) into a dedicated namespace. Adapter packages (apcore-mcp, apcore-a2a, apcore-cli) should read from this namespace rather than using independent logging defaults
    • sys_modules (APCORE_SYS) — Promotes apcore.sys_modules.* flat keys into a dedicated namespace. register_sys_modules() prefers config.namespace("sys_modules") in namespace mode with config.get("sys_modules.*") legacy fallback
  • Event Type Naming and Collision Fix (§9.16) — Resolves two confirmed collisions in apcore-python's emitted event types:

    • "module_health_changed" was used for two distinct events (toggle on/off vs. error rate recovery); replaced by canonical names apcore.module.toggled and apcore.health.recovered
    • "config_changed" was used for two distinct events (key update vs. module reload); replaced by apcore.config.updated and apcore.module.reloaded
    • Establishes dot-namespaced naming convention: apcore.* reserved for core, apcore-mcp.* / apcore-a2a.* / apcore-cli.* for adapters
    • All four legacy short-form names remain emitted as aliases during transition

v0.16.0

15 Apr 08:42

Choose a tag to compare

[0.16.0] - 2026-04-03

Added

Config Bus Enhancements

  • env_style parameter — Three modes for environment variable key conversion: auto (default, matches against defaults tree), nested (single _.), flat (no conversion). Resolves flat snake_case config key conflicts.
  • max_depth parameter — Limits nesting depth for env var key conversion (default: 5). Prevents excessively deep nesting from long env var names.
  • env_prefix auto-derivation — When env_prefix is not provided, auto-derived from namespace name via name.upper().replace("-", "_").
  • env_map parameter — Explicit mapping of bare (unprefixed) env var names to config keys within a namespace (e.g., {"REDIS_URL": "cache_url"}).
  • Config.env_map() class method — Global bare env var → top-level config key mapping (e.g., {"PORT": "port"}).
  • CONFIG_ENV_MAP_CONFLICT error — Raised when the same env var is claimed by multiple env_map registrations.

Context Redesign

  • ContextKey<T> typed accessor — Generic type-safe wrapper for context.data access with get(), set(), delete(), exists(), scoped() methods. Available in Python, TypeScript, and Rust.
  • Built-in context key constantsTRACING_SPANS, TRACING_SAMPLED, METRICS_STARTS, LOGGING_START, REDACTED_OUTPUT, RETRY_COUNT_BASE exported for middleware authors.
  • _context_version serialization — Context serialization now includes _context_version: 1 for forward compatibility. Deserialization warns on unknown versions but proceeds.
  • Context serialize() / deserialize() methods — Explicit serialization API with data key filtering (underscore-prefixed keys excluded).

Annotations Extension

  • extra field on ModuleAnnotations — Free-form extension dictionary for ecosystem packages and user metadata (e.g., extra={"mcp.category": "tools"}).
  • pagination_style type relaxed — Changed from Literal["cursor", "offset", "page"] to open string, allowing custom pagination strategies.
  • DEFAULT_ANNOTATIONS constant — Exported frozen default annotations instance.
  • from_dict() classmethod (Python) — Deserializes annotations with unknown keys captured in extra.
  • createAnnotations() factory (TypeScript) — Convenience factory accepting partial overrides.
  • Canonical snake_case wire format (TypeScript) — annotationsToJSON() / annotationsFromJSON() for cross-language serialization.

ACL Condition Handlers

  • ACLConditionHandler protocol — Extensible condition evaluation interface. Python: sync + async protocols. TypeScript: boolean | Promise<boolean>. Rust: #[async_trait].
  • ACL.register_condition() class method — Register custom condition handlers (e.g., ip_range, time_window).
  • $or and $not compound operators — Built-in compound condition handlers for OR and NOT logic in ACL rules.
  • async_check() method — Async ACL check alongside existing sync check(), supporting async condition handlers.
  • Fail-closed for unknown conditions — Unknown condition keys now log a warning and return False (deny), instead of being silently ignored.

Execution Pipeline Strategy

  • Step protocol / interface / trait — Pluggable pipeline step with name, description, removable, replaceable, and async execute().
  • ExecutionStrategy class — Ordered list of steps with insert_after(), insert_before(), remove(), replace() modification API.
  • PipelineEngine — Executes strategy steps with index-based loop, skip_to support, trace accumulation, and abort handling.
  • PipelineTrace / StepTrace — Complete execution trace for AI introspection and learning.
  • 11 built-in stepsBuiltinContextCreation, BuiltinSafetyCheck, BuiltinModuleLookup, BuiltinACLCheck, BuiltinApprovalGate, BuiltinInputValidation, BuiltinMiddlewareBefore, BuiltinExecute, BuiltinOutputValidation, BuiltinMiddlewareAfter, BuiltinReturnResult.
  • Preset strategiesbuild_standard_strategy() (11 steps), build_internal_strategy() (skip ACL/approval), build_testing_strategy() (minimal), build_performance_strategy() (skip middleware).
  • Executor.strategy parameter — Optional, backward-compatible. When omitted, uses standard 11-step pipeline.
  • call_with_trace() / call_async_with_trace() — Returns (result, PipelineTrace) tuple for observability.
  • register_strategy() / list_strategies() / describe_pipeline() — Strategy introspection API.

Changed

  • Data key naming convention — Internal middleware keys migrated from legacy names (_metrics_starts, _usage_starts, _obs_logging_starts) to _apcore.mw.* convention. All middleware now uses typed ContextKey constants.

Fixed

  • Rust ApprovalRequest spec alignment — Added required context field (Option<Context<Value>>) and changed annotations type from HashMap to ModuleAnnotations per spec §7.3.1.
  • Rust DependencyInfo field rename — Renamed name to module_id for cross-SDK consistency with Python/TypeScript.
  • Rust config env fallback — Fixed namespace-mode APCORE_* env var fallback to resolve to top-level paths instead of incorrectly prepending apcore. prefix.
  • Rust config_env conformance test — Added missing conformance test (was 9/10, now 10/10 fixtures).
  • Rust Context field alignment — Removed non-spec fields (created_at, parent_trace_id, trace_context). Changed global_deadline from Option<Instant> to Option<f64> (epoch seconds).
  • Rust Identity immutability — Fields made private with pub getters. Serde compatibility via IdentityRaw pattern.
  • TypeScript globalDeadline field — Added globalDeadline: number | null to Context (was missing).
  • Rust system.control module — Extracted into dedicated control.rs file (was inline in mod.rs).
  • TypeScript removeRule comparison — Fixed to use element-wise array comparison instead of JSON.stringify.
  • Rust empty callers matching — Empty callers list now matches none (aligned with Python/TypeScript).
  • API documentation audit (13 fixes) — Corrected Executor constructor (missing strategy param), cache_key_fields type (tuple not list), ModuleAnnotations.extra field, Reserved Words, extensions_dir default, ModuleExample defaults, Context serialize()/deserialize(), _global_deadline, preflight()/describe() methods, PreflightCheckResult.warnings, $or/$not ACL examples.
  • Cross-language tabbed examples — Added TypeScript tab to system-modules.md, converted client-api.md to 3-language tabs, fixed bare code blocks in 4 API docs.

Release 0.14.0 (2026-03-24)

25 Mar 03:00

Choose a tag to compare

Fixed

Specification Documents

  • docs/features/event-system.md — Fixed severity levels from warning/critical to warn/fatal, aligning with PROTOCOL_SPEC §10.2
  • docs/features/core-executor.md — Fixed Identity description: removed incorrect permissions field, corrected to id, type, roles, attrs per PROTOCOL_SPEC §5.7
  • docs/features/core-executor.md — Added missing ApprovalPendingError to Approval Gate description per PROTOCOL_SPEC §7.4
  • docs/features/middleware-system.md — Added retry.py to Key Files table (was described in Components but missing from file list)
  • docs/features/observability.md — Added concrete metric names (apcore_module_calls_total, apcore_module_errors_total, apcore_module_duration_seconds) to convenience method documentation

Protocol Specification

  • Fixed duplicate ### 10.5 section numbering — renumbered Sensitive Data Redaction to §10.6, Sampling Strategy to §10.7, Span Naming Convention to §10.8
  • Fixed ### 8.1.1 misnumbered under §9.1 — corrected to §9.1.1
  • Fixed ### 10.8.x misnumbered under §11.8 — corrected to §11.8.1–§11.8.4
  • Fixed middleware priority model contradiction between §11.2 (explicit 0-1000) and §12 (registration order) — §12 now aligns with §11.2
  • Fixed on_error examples in README.md and concepts.md — changed raise error to correct return-based contract (return None / return dict)
  • Updated "Last Updated" date to 2026-03-24

Scope Document

  • Added Approval System (§7) and Event System to "Core Protocol Includes" list in SCOPE.md

README

  • Added AI-Perceivable brand definition block to README header
  • Added "Perceived → Understood → Executed" progression table to "Why AI-Perceivable?" section

Ecosystem

§5.13 Display Overlay (specified in v0.13.0) is now implemented across the official adapter stack:

Package Version What was implemented
apcore-toolkit 0.4.0 DisplayResolver — §5.13 resolve priority chain, MCP alias sanitization/64-char limit, CLI alias validation, suggested_alias fallback, binding_path file/directory loading
apcore-cli 0.3.0 CLI command routing from metadata["display"]["cli"]["alias"]; descriptor cache; JSON output reads display overlay
apcore-mcp 0.11.0 MCP tool name and description from metadata["display"]["mcp"]; guidance appended to tool description
apcore-a2a 0.3.0 A2A skill id/description/tags from metadata["display"]["a2a"]; removed dead _build_extensions()
fastapi-apcore 0.4.0 binding_path parameter on create_cli() / create_mcp_server(); DeprecationWarning for simplify_ids=True
  • §5.14 Convention Module Discovery — new optional protocol capability for zero-decorator module registration via commands/ directory convention.