Python ↔ TypeScript parity matrix¶
Generated — not hand-kept
This page is generated by scripts/gen_parity_matrix.py from the same fixtures that the CI parity suites enforce
(tests/parity-fixtures/port-surface-parity.json and packages/sdk-ts/kind-registry-parity.json). The docs build regenerates it,
so the published matrix and the enforced contract cannot drift. Do not edit it by hand.
DNA ships a Python SDK and a TypeScript SDK that are behaviorally identical. This matrix is the published proof — in the spirit of the OpenTelemetry spec-compliance matrix, it lists each contract member as a row and each language as a column, so "1:1 parity" is shown, not asserted.
Legend
- ✅ — implemented on this side.
- ⚠️ — intentionally absent on this side; the asymmetry is documented (see the Notes column). Undocumented drift reds the parity suite in CI.
- ➖ — not applicable / shaped differently by design.
Summary: 152 shared members across the tracked contracts, 39 documented asymmetries. Python is the semantic reference: a gap is closed by porting to TypeScript, or justified in the fixture — never by silence.
Ports — the microkernel contract¶
Each port is a typing.Protocol (Python) / interface (TypeScript). Rows are the contract members; a ✅ in both columns means the twin exists (Python members are snake_case, their TypeScript twins camelCase). The Python suite introspects the real Protocol members; the TypeScript suite is keyof-bound to the real interfaces, so tsc fails on drift.
SourcePort¶
WHERE — load documents from storage. Py: dna/kernel/protocols.py · TS: src/kernel/protocols.ts
| Member | Python | TypeScript | Notes |
|---|---|---|---|
supports_readers |
✅ | ✅ | |
load_bootstrap_docs |
✅ | ✅ | |
load_all |
✅ | ✅ | |
resolve_ref |
✅ | ✅ | |
load_layer |
✅ | ✅ | |
close |
✅ | ✅ | ℹ️ Py lists close in SOURCE_PORT_CORE_MEMBERS (boot gate); TS declares it optional — the kernel treats a missing close as a no-op. FS adapters implement a documented no-op; the SQL adapters end what they own (Py SqlAlchemySource disposes its engine; TS raw PostgresSource closes its pool). |
list_doc_refs |
✅ | ✅ | ℹ️ L1 granular read, capability-mediated on both sides (SourceCapabilities.granular_list / granularList). |
load_one |
✅ | ✅ | |
query |
✅ | ✅ | |
count |
✅ | ✅ | |
capabilities |
⚠️ | ✅ | TS declares capabilities() on the READ port so read-only adapters (FilesystemSource TS has no write half) can declare explicitly; Py declares it on WritableSourcePort because every in-repo Py adapter is writable. Same contract, different attachment point — see the WritableSourcePort py-only twin entry. |
WritableSourcePort¶
SourcePort + write/versioning half. OWN members only (inherited SourcePort members are tracked above).
| Member | Python | TypeScript | Notes |
|---|---|---|---|
save_document |
✅ | ✅ | |
delete_document |
✅ | ✅ | |
list_versions |
✅ | ✅ | |
get_version |
✅ | ✅ | |
publish |
✅ | ✅ | ℹ️ PG TS is a documented single-step no-op (no draft state); the member exists so Draftable-style flows type-check. |
save_manifest |
✅ | ⚠️ | Py-only: whole-manifest persistence backs the Py scope-seed/sync machinery (source_sync, dna doc apply). The TS SDK has no manifest-write pipeline — adding the member without the machinery would be a lying surface. |
load_drafts |
✅ | ⚠️ | Py-only: the draft→publish lifecycle (Draftable capability) exists only in the Py adapters. TS adapters declare drafts:false in SourceCapabilities; PG TS publish() is a documented single-step no-op. |
list_scopes |
✅ | ⚠️ | Py-only: consumed by the Catalog tier scan and scope enumeration endpoints (kinds-api), which are Py-only runtime surfaces. No TS consumer exists (composition parity case 10 is skip_ts for the same reason). |
capabilities |
✅ | ⚠️ | Cross-attachment twin of the SourcePort ts-only capabilities entry: TS declares capabilities() on SourcePort (read-only adapters declare too); Py declares it here. One contract, tracked once per side. |
CachePort¶
WHERE — store/retrieve installed deps.
| Member | Python | TypeScript | Notes |
|---|---|---|---|
load_all |
✅ | ✅ | |
load_key |
✅ | ✅ | |
store |
✅ | ✅ | |
has |
✅ | ✅ |
ResolverPort¶
FROM — fetch external deps.
| Member | Python | TypeScript | Notes |
|---|---|---|---|
resolve |
✅ | ✅ | |
cache_key |
✅ | ✅ |
ReaderPort¶
Reads a bundle and produces a raw dict.
| Member | Python | TypeScript | Notes |
|---|---|---|---|
detect |
✅ | ✅ | |
read |
✅ | ✅ | |
_owner_container |
✅ | ✅ |
WriterPort¶
Writes a raw dict back to a bundle. Inverse of ReaderPort.
| Member | Python | TypeScript | Notes |
|---|---|---|---|
can_write |
✅ | ✅ | |
write |
✅ | ✅ | |
serialize |
✅ | ✅ |
KindPort¶
WHO — identity + composition role.
| Member | Python | TypeScript | Notes |
|---|---|---|---|
api_version |
✅ | ✅ | |
kind |
✅ | ✅ | |
alias |
✅ | ✅ | |
origin |
✅ | ✅ | |
storage |
✅ | ✅ | |
is_root |
✅ | ✅ | |
is_prompt_target |
✅ | ✅ | |
prompt_target_priority |
✅ | ✅ | |
flatten_in_context |
✅ | ✅ | |
is_runtime_artifact |
✅ | ✅ | |
dep_filters |
✅ | ✅ | |
dependencies |
✅ | ✅ | |
schema |
✅ | ✅ | |
get_default_agent_name |
✅ | ✅ | |
get_layer_policies |
✅ | ✅ | |
parse |
✅ | ✅ | |
describe |
✅ | ✅ | |
summary |
✅ | ✅ | |
prompt_template |
✅ | ✅ | |
model |
✅ | ⚠️ | Py-only: the Pydantic model class attribute drives Py's parse/validation. TS kinds hold their Zod schema internally and expose it via schema() — a model member would have no uniform TS meaning. |
scope |
⚠️ | ✅ | TenantScope declaration. Py documents it as an optional duck-typed attr (kernel getattr's it; kept off the Protocol so isinstance stays permissive for third-party Kinds); TS interfaces express optional members natively. |
docs |
⚠️ | ✅ | KindPresentation slice member — TS KindPort extends KindPresentation (keyof includes it, so the exhaustive manifest lists it here too); the Py twin lives on the KindPresentation capability Protocol, kept OFF the runtime_checkable KindPort so the H1 isinstance gate never requires it. Tracked as a py↔ts pair in the KindPresentation port below. |
isSchemaAffecting |
⚠️ | ✅ | Kernel classification attr (s-kernel-kindport-classification-attrs). Py derives via getattr with defaults off KindBase; TS declares the optional member on the interface. |
isOverlayable |
⚠️ | ✅ | Same classification-attrs rationale as isSchemaAffecting. |
scopeInheritable |
⚠️ | ✅ | Same classification-attrs rationale as isSchemaAffecting. |
plane |
⚠️ | ✅ | Two-planes marker (record|composition). Py reads it duck-typed off descriptors/KindBase; TS declares the optional member. |
preview |
⚠️ | ✅ | KindPresentation slice member — see the docs entry above; paired in the KindPresentation port below. |
graphStyle |
⚠️ | ✅ | KindPresentation slice member — see the docs entry above; paired in the KindPresentation port below. |
asciiIcon |
⚠️ | ✅ | KindPresentation slice member — see the docs entry above; paired in the KindPresentation port below. |
displayLabel |
⚠️ | ✅ | KindPresentation slice member — see the docs entry above; paired in the KindPresentation port below. |
graphMeta |
⚠️ | ✅ | KindPresentation slice member — see the docs entry above; paired in the KindPresentation port below. |
uiSchema |
⚠️ | ✅ | KindPresentation slice member — see the docs entry above; paired in the KindPresentation port below. |
descriptionFallbackField |
⚠️ | ✅ | KindPresentation slice member — see the docs entry above; paired in the KindPresentation port below. |
visibleInBackend |
⚠️ | ✅ | KindPresentation slice member (was read via (kp as any).visibleInBackend before s-dna-kindport-descriptor-schema declared it) — see the docs entry above; paired in the KindPresentation port below. |
KindPresentation¶
Optional presentation/UX capability of a Kind (s-dna-kindport-descriptor-schema). Py: typing-only capability Protocol (NOT runtime_checkable, NOT part of KindPort — the H1 isinstance gate must never require these; the is_runtime_artifact precedent). TS: interface that KindPort extends (native optional members). Every member is optional at runtime; KindBase carries the attribute defaults; consumers use typed access with a default (getattr(kp, name, None) / kp.member?.).
| Member | Python | TypeScript | Notes |
|---|---|---|---|
docs |
✅ | ✅ | |
description_fallback_field |
✅ | ✅ | |
ui_schema |
✅ | ✅ | |
graph_style |
✅ | ✅ | |
ascii_icon |
✅ | ✅ | |
display_label |
✅ | ✅ | |
visible_in_backend |
✅ | ✅ | |
preview |
✅ | ✅ | |
graph_meta |
✅ | ✅ |
ToolPort¶
An invocable tool exposed to agents + DNA discovery metadata (s-dna-tool-decorator; TS twin landed with s-dna-port-surface-parity).
| Member | Python | TypeScript | Notes |
|---|---|---|---|
name |
✅ | ✅ | |
group |
✅ | ✅ | |
description |
✅ | ✅ | |
summary |
✅ | ✅ | |
args_schema |
✅ | ✅ | |
hitl |
✅ | ✅ | |
scope |
✅ | ✅ | |
source |
✅ | ✅ | |
get_callable |
✅ | ✅ |
ExtensionHost¶
The registration-time surface the Kernel offers to Extension.register() (s-dna-extension-host-contract).
| Member | Python | TypeScript | Notes |
|---|---|---|---|
hooks |
✅ | ✅ | |
kind |
✅ | ✅ | |
kind_from_descriptor |
✅ | ✅ | |
reader |
✅ | ✅ | |
writer |
✅ | ✅ | |
on |
✅ | ✅ | |
on_veto |
✅ | ✅ | |
tool |
✅ | ✅ | |
composition_profile |
✅ | ✅ |
Extension¶
Registers kinds, readers, and writers on the Kernel.
| Member | Python | TypeScript | Notes |
|---|---|---|---|
name |
✅ | ✅ | |
version |
✅ | ✅ | |
register |
✅ | ✅ | |
templates |
⚠️ | ✅ | Py keeps templates() OFF the Extension Protocol (separate TemplateProvider Protocol, feature-tested) so legacy pre-Phase-0 extensions keep satisfying isinstance(ext, Extension); TS expresses the same back-compat with a native optional member. See the TemplateProvider py-only port. |
TemplateProvider¶
Optional Extension capability — ships scaffold file trees. Py-only Protocol; TS folds the member into Extension.templates?.
| Member | Python | TypeScript | Notes |
|---|---|---|---|
templates |
✅ | ⚠️ | TS has no separate TemplateProvider interface: the optional Extension.templates? member IS the TS twin (tracked in the Extension port above). A second interface would add nothing in a structurally-typed language. |
RecordSearchProvider¶
Two-planes F2 — semantic search over record docs, registered on the kernel at app boot.
| Member | Python | TypeScript | Notes |
|---|---|---|---|
search |
✅ | ✅ |
EmbeddingPort¶
rec-embedding-port — text→dense-vector, sibling to RecordSearchProvider. Fake floor is zero-dep + bit-exact Py↔TS; ONNX all-MiniLM-L6-v2 is an opt-in extra. Py: dna/kernel/protocols.py · TS: src/kernel/protocols.ts
| Member | Python | TypeScript | Notes |
|---|---|---|---|
model_id |
✅ | ✅ | |
dims |
✅ | ✅ | |
embed |
✅ | ✅ |
SourceCapabilities¶
Typed declaration of what a source adapter supports (s-sourceport-contract-cleanup). Members are dataclass fields (Py) / interface keys (TS).
| Member | Python | TypeScript | Notes |
|---|---|---|---|
source |
✅ | ✅ | |
drafts |
✅ | ✅ | |
versions |
✅ | ✅ | |
layers |
✅ | ✅ | |
bundle_read |
✅ | ✅ | |
bundle_write |
✅ | ✅ | |
kernel_attachable |
✅ | ✅ | |
granular_list |
✅ | ✅ | |
granular_one |
✅ | ✅ | |
query_pushdown |
✅ | ✅ | |
tenant_layer_writes |
✅ | ⚠️ | Python-signature concept: optional kwargs must be probed via inspect.signature, so Py declares which write kwargs an adapter accepts. The TS write surface is an options bag — nothing to probe (already documented in capabilities.ts). |
write_kwargs |
✅ | ⚠️ | Same rationale as tenant_layer_writes — Py kwarg vocabulary declaration; meaningless in TS. |
delete_kwargs |
✅ | ⚠️ | Same rationale as tenant_layer_writes — Py kwarg vocabulary declaration; meaningless in TS. |
CapabilityProtocols¶
Exported optional-capability Protocols (Py capabilities.py) / interfaces (TS capabilities.ts). Members here are the PROTOCOL NAMES, not method names.
| Member | Python | TypeScript | Notes |
|---|---|---|---|
BundleEntryReadable |
✅ | ✅ | |
KernelAttachable |
✅ | ✅ | |
Versionable |
✅ | ✅ | |
BundleEntryWritable |
✅ | ⚠️ | Py-only: no TS adapter has a bundle-WRITE path (every TS SourceCapabilities declares bundleWrite:false). The interface lands together with the first TS bundle-write implementation, not before. |
Draftable |
✅ | ⚠️ | Py-only: the draft store exists only in Py adapters (see WritableSourcePort.load_drafts justification). |
Layered |
✅ | ⚠️ | Py-only: granular per-doc load_layer(scope, layer, kind, name) resolution consumed by the Py harness overlay reads; the TS SourcePort.loadLayer (whole-layer) covers the TS composition engine's needs. |
TenantAware |
✅ | ⚠️ | Documentation/static-typing Protocol for Python's kwarg-level write contract — TS options-bag writes need no kwarg protocol (same rationale as SourceCapabilities.write_kwargs). |
LayerAware |
✅ | ⚠️ | Same rationale as TenantAware. |
Blessed query surface — the public read API¶
The blessed members are the ONE documented way to read manifest data; deprecated members still work but warn and are removed in 1.0. Adding, renaming or removing any public member without editing the fixture reds the suite.
ManifestInstance — blessed¶
| Member | Python | TypeScript | Notes |
|---|---|---|---|
documents |
✅ | ✅ | ℹ️ canonical in-memory read — filter/find by d.kind / d.name; what QUICK-START, READMEs and examples teach |
root |
✅ | ✅ | |
default_agent |
✅ | ✅ | |
find_agent |
✅ | ✅ | |
build_prompt |
✅ | ✅ | |
build_prompt_async |
✅ | ⚠️ | Py sync/async split — TS buildPrompt is already async; Py needs an explicit async twin so event-loop callers keep pool-based sources loop-bound. |
resolve |
✅ | ✅ | |
resolve_async |
✅ | ⚠️ | Py sync/async split — TS resolve is sync over in-memory layers; the Py async twin exists for the same loop-binding reason as build_prompt_async. |
all_async |
✅ | ⚠️ | Py-only async bridge returning parsed Documents — record-plane, tenant and inheritance aware. TS has no lazy/record MI split; TS callers use mi.documents or kernel.query. |
one_async |
✅ | ⚠️ | single-doc twin of all_async — delegates to kernel.get_document (L2-cached). |
ManifestInstance — deprecated (removed in 1.0)¶
| Member | Python | TypeScript | Replacement |
|---|---|---|---|
all |
✅ | ✅ | mi.documents (filter by d.kind) or kernel.query(scope, kind) |
one |
✅ | ✅ | mi.documents (find by d.kind + d.name); Py also kernel.get_document(scope, kind, name), TS kernel.query with a filter |
The exact public ManifestInstance surface is pinned member-for-member by the fixture: 55 Python members and 55 TypeScript members. Any public addition/removal/rename on either side without a matching fixture edit reds the suite.
Kernel — blessed¶
| Member | Python | TypeScript | Notes |
|---|---|---|---|
instance |
✅ | ✅ | ℹ️ entry point — loads/returns the scope's ManifestInstance |
instance_async |
✅ | ⚠️ | Py sync/async split — TS instance() is already async. |
query |
✅ | ✅ | ℹ️ indexed / record-plane read — push-down to the source, raw rows |
count |
✅ | ✅ | ℹ️ aggregation twin of query |
get_document |
✅ | ⚠️ | TS kernel has no getDocument — TS single-doc reads go through mi.documents or kernel.query with a filter; port when a TS caller needs the L2-cached single-doc read. |
query_list_sync |
✅ | ⚠️ | Py-only loop-safety wrapper returning parsed Documents for sync callers (CLI, workers). TS is async-native — no sync bridge needed. |
get_document_sync |
✅ | ⚠️ | single-doc twin of query_list_sync. |
Hook names — the shared event vocabulary¶
The HookRegistry hook-name vocabulary is identical on both sides (event names are wire vocabulary, not API casing).
| Hook | Python | TypeScript |
|---|---|---|
pre_build_prompt |
✅ | ✅ |
post_build_prompt |
✅ | ✅ |
pre_save |
✅ | ✅ |
post_save |
✅ | ✅ |
post_delete |
✅ | ✅ |
kinddef_conflict |
✅ | ✅ |
parse_error |
✅ | ✅ |
extension_error |
✅ | ✅ |
Kind registry — class-backed Kinds¶
Class-backed builtin Kinds registered on both runtimes. Descriptor-backed Kinds (*/kinds/*.kind.yaml, byte-identical Py↔TS package data) are byte-parity by construction and deliberately absent from this list — they cannot drift. py_only_allowlist Kinds are registered in Python (entry-points) and intentionally not yet ported to TypeScript.
| Kind (alias) | Python | TypeScript | Notes |
|---|---|---|---|
agentskills-skill |
✅ | ✅ | |
agentsmd-agent |
✅ | ✅ | |
audit-userroleassignment |
✅ | ✅ | |
evidence-policy |
✅ | ✅ | |
federation-mcp |
✅ | ✅ | |
guardrails-guardrail |
✅ | ✅ | |
helix-actor |
✅ | ✅ | |
helix-agent |
✅ | ✅ | |
helix-canvas |
✅ | ✅ | |
helix-genome |
✅ | ✅ | |
helix-hook |
✅ | ✅ | |
helix-safety-policy |
✅ | ✅ | |
helix-setting |
✅ | ✅ | |
helix-theme |
✅ | ✅ | |
helix-tool |
✅ | ✅ | |
helix-usecase |
✅ | ✅ | |
helix-user-profile |
✅ | ✅ | |
kinddef-kinddefinition |
✅ | ✅ | |
lesson-lesson |
✅ | ✅ | |
policy-layer-policy |
✅ | ✅ | |
presidio-recognizer |
✅ | ✅ | |
research-research |
✅ | ✅ | |
sdlc-agent-session |
✅ | ✅ | |
sdlc-bug |
✅ | ✅ | |
sdlc-epic |
✅ | ✅ | |
sdlc-feature |
✅ | ✅ | |
sdlc-initiative |
✅ | ✅ | |
sdlc-issue |
✅ | ✅ | |
sdlc-plan |
✅ | ✅ | |
sdlc-reference |
✅ | ✅ | |
sdlc-roadmap |
✅ | ✅ | |
sdlc-spec |
✅ | ✅ | |
sdlc-spike |
✅ | ✅ | |
sdlc-story |
✅ | ✅ | |
sdlc-task |
✅ | ✅ | |
soulspec-soul |
✅ | ✅ | |
tenant-membership |
✅ | ✅ | |
tenant-tenant |
✅ | ✅ | |
testkit-test-guide |
✅ | ✅ | |
testkit-test-run |
✅ | ✅ | |
collab-comment |
✅ | ⚠️ | Python-only (entry-point registered); documented in the registry allowlist, not yet ported to TypeScript. |
Excluded surfaces — deliberately not parity-tracked¶
Surfaces where member parity is intentionally NOT enforced, each with a recorded reason. ➖ marks the side where the surface is absent or shaped differently on purpose.
| Surface | Python | TypeScript | Reason |
|---|---|---|---|
collaborator-ports |
✅ | ✅ | Kernel INTERNALS, not public contract: these are the narrow mediator slices from the kernel-decomposition epic (e-kernel-decomposition). Each language decomposed its own god-object along its own seams (Py ~15 slices, TS 3) — forcing member parity here would couple internal refactors across languages for zero user-facing value. |
dna_tool-decorator |
✅ | ➖ | The @dna_tool decorator + pending-tools harvest is langchain glue (wraps langchain_core.tools.tool for langgraph/deepagents). The TS SDK has no langchain runtime; the portable part — ToolPort/ToolDefinition + ToolRegistry + kernel.tool()/getTools() and the read-umbrella group aliases — IS ported and surface-tracked above. |
Behavioral proof — the conformance kit¶
This matrix proves the two SDKs expose the same surface. That they behave the same is proven separately by the dna.testing conformance kits — source and reader/writer conformance suites that run the identical scenarios against both runtimes. See Running the conformance kit, and the guides on reading document data and writing a source adapter for the contracts these tables enforce.