-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Summary
Real-world integrations (tiptap-apcore, nestjs-apcore, django-apcore) revealed several gaps in PROTOCOL_SPEC.md that caused cross-implementation incompatibilities. This issue tracks the protocol-level additions needed.
Issues Addressed
1. Module ID Format Constraint (P0 — from tiptap-apcore ISSUE-002)
Problem: The spec did not restrict characters in module_id. The MCP/OpenAI normalizer converts dots to hyphens (image.resize → image-resize), but module IDs containing hyphens (e.g., my-app.toggle-bold) cannot be round-tripped. The normalization is lossy.
Fix: Add a regex constraint to the spec:
^[a-z][a-z0-9_]*(\.[a-z][a-z0-9_]*)*$
Hyphens are explicitly prohibited — reserved for dot→hyphen normalization (must be bijective).
2. Cross-Language Naming Conventions (P0 — from tiptap-apcore mega-finding)
Problem: No cross-language binding rules defined. apcore-typescript uses camelCase (moduleId, getDefinition()) while apcore-mcp-typescript used snake_case (module_id, get_definition()). The two packages were incompatible without a shim.
Fix: Add a naming convention mapping table:
| Protocol (canonical) | TypeScript | Python |
|---|---|---|
module_id |
moduleId |
module_id |
input_schema |
inputSchema |
input_schema |
call_async() |
callAsync() |
call_async() |
get_definition() |
getDefinition() |
get_definition() |
3. Standard Registry Event Names (P0 — from tiptap-apcore ISSUE-001, django-apcore Django-2.5)
Problem: No standard event names defined. Each implementation used different names ("register", "module:registered", etc.), making RegistryListener and cross-implementation interoperability impossible.
Fix: Define two standard events with callback signatures:
| Event | Triggered | Callback |
|---|---|---|
"register" |
After module registered | (module_id, module) -> None |
"unregister" |
Before module removed | (module_id, module) -> None |
All SDKs MUST export as named constants (REGISTRY_EVENTS.REGISTER / REGISTRY_EVENTS["REGISTER"]).
4. Error Code Constants Export Requirement (P1 — from tiptap-apcore ISSUE-003)
Problem: Error codes were magic strings. ErrorMapper checks error.code === "ACL_DENIED" via hardcoded strings with no exported constants.
Fix: All SDKs MUST export an ErrorCodes constant with all framework error codes from Section 7.
5. ContextFactory Protocol (P0 — from django-apcore Django-2.1)
Problem: No standard adapter pattern for creating Context from HTTP requests. Every framework integration (Django, Flask, NestJS) invented its own approach.
Fix: Define ContextFactory protocol: create_context(request) -> Context.
Affected Sections
- Section 3 (Module ID definition) — lines 195, 201-220
- New section: Cross-Language Naming Conventions — lines 3834-3848
- New section: Standard Registry Event Names — lines 3850-3859
- New section: Error Code Constants Export Requirement — lines 3861-3872
- New section: Context Factory Protocol — lines 3874-3885
Source
apcore-mcp-typescript/docs/issues/tiptap-apcore-findings.md(ISSUE-001, ISSUE-002, ISSUE-003, naming mega-finding)django-apcore/docs/django-apcore/upstream-sdk-analysis.md(Django-2.1, Django-2.5)nestjs-apcore/docs/upstream-improvements.md(event mechanism, context passing)