ErisPulse RFC EPRFC-2026-001 — ErisPulse 2.9.0 Roadmap Direction / ErisPulse 2.9.0 方向定调 #439
Replies: 1 comment
Directions 1–9 are delivered on 方向 1–9 已交付至
A note on direction 5: the dispatch decision chain is also exposed to tests — 关于方向五补充一句:分发决策链同时暴露给了测试—— Remaining on the 2.9.0 line: ORM MySQL / PostgreSQL real-machine verification (SQLite passed), ecosystem compatibility checks (ErisPulse-Dashboard, core adapters), then soak and cut 2.9.0 final. Feedback questions above remain open. 2.9.0 线上剩余:ORM MySQL / PostgreSQL 真机验证(SQLite 已通过)、生态兼容验证(ErisPulse-Dashboard、核心适配器)、dev 浸泡后收口 2.9.0 正式版。上方反馈问题持续开放。 Before 2.9.0 final / 正式版收尾清单
ErisPulse Core Team — 2026-09-21 / 2026-09-24 修订(全量交付状态;主帖交付表述已迁入本评论) |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
ErisPulse RFC EPRFC-2026-001 — ErisPulse 2.9.0 Roadmap Direction / ErisPulse 2.9.0 方向定调
What 2.9 Covers / 一、2.9 要解决什么
ErisPulse 2.8 established the framework foundations (access scopes, multi-database storage, module RPC, lifecycle events). 2.9 focuses on the module development experience — turning every piece of boilerplate that every module author hand-writes into declarative framework capability:
ErisPulse 2.8 建立了框架能力基础(权限作用域、多数据库存储、模块间调用、生命周期事件)。2.9 聚焦**"写模块的体验"**——把每个模块作者都在手写的样板代码,上收为框架的声明式能力:
args=+options=)1. Command Argument Parsing / 二、命令参数解析
Today / 现在的写法:
In 2.9 / 2.9 的写法:
Behavior / 行为说明:
args=as proposed:str,int,float,bool,literal(enum),duration(e.g.90s,1h30m),rest/args=维持原提案:str、int、float、bool、literal(枚举)、duration(如90s、1h30m)、rest(剩余全部文本)options=dict declaration: key = handler parameter name, value = flag form(s).-v/--verbose= boolean flag;--label= valued option (--label helloor--label=hello), type follows the handler annotation /options=字典声明:键 = 处理器参数名,值 = 旗标形式。-v/--verbose为布尔旗标;--label为带值选项(--label hello或--label=hello),类型跟随处理器注解args=(sorestcovers the text left after option removal) / 选项先被识别剔除,剩余 token 再交给args=解析(rest为剔除选项后的剩余文本)args=+options=auto-generate usage text (including options) shown by the built-in help command / 自动生成 usage(含选项),/help命令自动展示args=/options=, behavior is unchanged / 现有模块完全不受影响,不写即原行为Not in this version / 本版本不包含:platform-specific types such as
user/group(require adapter support, planned for later versions / 需要各适配器配合,后续版本支持);Chinese duration units such as5分钟(planned via optional language packs / 后续通过可选语言包支持)。2. Dependency Injection / 三、依赖注入
Today / 现在的写法:
In 2.9 / 2.9 的写法:
3. Testing Toolkit / 四、测试框架(独立包 ErisPulse-Testing)
2.9 ships an official testing toolkit. Writing a module test becomes:
2.9 提供官方测试工具,写模块测试只需:
Provides simulated command/message events, reply recording, and temporary dependency replacement, working together with pytest.
提供:模拟命令/消息事件、记录机器人回复、临时替换依赖等能力,与 pytest 配合使用。
4. Built-in Data Model Layer / 五、内置数据模型层(ORM)
Adjusted from the earlier draft / 与此前草案的差别:the ORM ships built into the framework (not as a separate package). Rationale: the ORM is built directly on the built-in storage layer (async-native, contextvar nested transactions, SQLite / MySQL / PostgreSQL), so they must co-evolve — a separate package would pin SDK versions and risk API drift, and would add an extra dependency for every module author. The storage three-backend test matrix doubles as the ORM verification base.
由独立包调整为框架内置。理由:ORM 直接构建在内置存储层之上(async 原生、contextvar 嵌套事务、SQLite / MySQL / PostgreSQL),二者必须同源演进——独立包意味着 SDK 版本钉子与 API 漂移风险,且给每个模块作者增加一层额外依赖。存储层的多后端测试矩阵天然成为 ORM 的验证基座。
Target capability / 目标能力:
Behavior / 行为说明:
Field()描述符(候选 B);配置基座保持@dataclass普通值不变,二者共享约束词表 / 校验器 / 类型类别注册表 / Decided: standaloneField()descriptors (candidate B); the config base keeps plain values, sharing the constraint vocabulary / validator engine / type-category registryRelationship with the declarative config layer / 与声明式配置层的关系:
Model declarations follow the same declarative style as the existing config class (
@dataclass+field(metadata=...)). The two domains share one field-declaration layer — but keep separate class bases by design:模型声明与既有声明式配置类(
@dataclass+field(metadata=...))采用同一声明风格。两个领域共享同一字段声明层,但类基座有意分立:max_length,ge/le) — one vocabulary consumed by both config and ORM / 字段元数据词表:默认值、描述(i18n 字典)、枚举、约束(max_length、ge/le)——配置与 ORM 消费同一词表@dataclass, TOML round-trip) — fixed; the model base shape is decided: descriptors with column expressions / 配置字段保持普通值(既定);模型基座形态已定:带列表达式的描述符Unifying the class bases themselves would force a breaking rewrite of every existing ConfigClass — deliberately not pursued. One declaration style, one shared field layer, two purpose-built bases / 不强行统一类基座——那将破坏性重写全部存量配置类。一份声明语法、一个共享字段层、两个各司其职的基座。
5. Module Troubleshooting / 六、模块排查
Pain point / 痛点:when a module "doesn't respond", you can only dig through logs / 模块"没反应"时,用户只能翻日志猜原因。
6. Middleware Event Veto / 七、中间件事件否决权
Today / 现在的行为:
Middleware runs sequentially before dispatch and can transform the event, but it cannot stop the event from being dispatched. Firewalls, rate limiters and similar scenarios can only be implemented as high-priority event handlers as a workaround — and handlers can only block lower-priority processors, not the event itself.
中间件在分发前顺序执行、可以改写事件,但无法阻止事件继续分发。防火墙、限流等场景只能注册高优先级事件处理器绕行实现——且处理器只能阻断更低优先级的处理器,无法在事件层面丢弃。
In 2.9 / 2.9 的行为:
Behavior / 行为说明:
Falsedrops the event immediately: no handlers run, no side effects / 返回False立即丢弃事件:不进入任何处理器,无任何出站副作用Nonekeeps today's semantics (payload unchanged) / 返回None保持现有语义(载荷不变)adapter.event.blockedlifecycle hook (carrying the middleware name) for troubleshooting / 否决时输出 TRACE 日志并触发adapter.event.blocked生命周期钩子(携带中间件名),便于排查"为什么事件没响应"Falsevetoes / 现有中间件完全不受影响——返回 None / dict 行为不变,仅显式返回False才否决Not in this version / 本版本不包含:negotiated veto (a later middleware overriding an earlier veto) / 后一个中间件推翻前一个否决的链式协商能力;if needed, it will be discussed in a follow-up issue / 如有需求将另开讨论。
7. Command Governance / 八、命令治理声明化(cooldown / rate_limit / usage_limit / deprecated)
Today / 现在的写法:
In 2.9 / 2.9 的写法:
Behavior / 行为说明:
args=durationtype (90s,1h30m,1d) / 按键控最小间隔;时长语法与args=的duration类型完全一致(90s、1h30m、1d)user/session/global— reuses the framework session-key infrastructure / 复用框架会话键体系(platform:bot:user:target)cooldown_replyprovides the reply text. The command is claimed either way — never leaks to lower-priority message handlers / 默认静默丢弃(对称于作用域静默语义);cooldown_reply可选回复文案。命中时命令同样被认领——不会漏给低优先级消息处理器"5/minute"); shares the limiter and session-key infrastructure with cooldown; router layer already has a precedent / 滑动窗口("5/minute");与冷却共享限流器与会话键基础设施;路由层已有先例"3/day"), aligned to the local timezone — distinct from the rate_limit sliding window / 业务用量配额,对齐本地时区自然周期("3/day");与 rate_limit 滑动窗口相区分deprecated_reject=Trueoptionally refuses execution / 帮助列表显示废弃标记;调用时自动回复废弃文案;deprecated_reject=True可选拒绝执行Not in this version / 本版本不包含:distributed / multi-process shared state, persistence across restarts / 跨进程共享状态与重启后持久化(后续版本视需求)。
8. Event Handler Declaratives / 九、事件处理器声明化(throttle / debounce)
Today / 现在的写法:
In 2.9 / 2.9 的写法:
Behavior / 行为说明:
throttle=, declaring both fails at registration / 窗口内多条消息只处理最后一条——以条件包装器实现(延迟执行 + 取消前序任务);与throttle=互斥,同时声明注册期抛错9. Config Env Mapping / 十、配置环境变量映射
Today / 现状:
Framework config already supports
ERISPULSE_*environment variable overrides — but module config does not. Docker / CI users must editconfig.tomlby hand or reados.environthemselves.框架配置已有
ERISPULSE_*环境变量覆盖——但模块自己的配置没有。Docker / CI 场景只能手改config.toml或自己读os.environ。In 2.9 / 2.9 的写法:
Behavior / 行为说明:
envmetadata, behavior is unchanged / 现有模块完全不受影响,不写 metadata 即原行为10. Module Reload Completeness / 十一、模块重载完备性(完全卸载、失败回滚与泄漏审计)
Today / 现状:
In 2.9 / 2.9 的行为:
Behavior / 行为说明:
load()— if any step fails, the previous instance is restored and service continues; best-effort semantics / 卸载、导入、load()任一步失败即恢复旧实例,服务不中断;尽力而为语义register_event_method) are reclaimed on module unload; a failedon_loadtriggers a half-unload so__init__side effects leave no orphan resources / 平台事件方法注入随模块卸载回收;on_load失败时执行半卸载,__init__副作用不残留(namespace, path)— same-path routes of other namespaces are no longer deleted / 按(namespace, path)精确注销,不再误删其它命名空间的同 path 路由gc.get_referrersholder identification; runs automatically after unload/reload; CLIepsdk audit [module](--jsonfor the Dashboard) / per-owner 资源只读计数 + 孤儿 owner 反向扫描(资源在、主人已注销)+ weakref 实例普查 +gc.get_referrers指认持有者;unload/reload 后自动运行;CLIepsdk audit [module](--json供 Dashboard)persist=Trueuser-config assets still survive unload (documented boundary unchanged); bare threads / third-party private containers remain out of reach — but become visible via the auditor / 纯新增只读 API;persist=True用户配置语义资产仍不随卸载清理(设计边界不变);裸线程 / 第三方私有容器引用依然清不掉——但从不可见变为可见11. Shadow Modules & Canary Promote / 十二、影子模块与灰度转正
Today / 现状:
No "trial run first, promote later" intermediate state — real group chats always cover what test environments miss.
没有「先试运行、再转正」的中间态——真实群聊的消息分布永远是测试环境覆盖不到的。
In 2.9 / 2.9 的写法:
The shadow instance runs as a separate owner (e.g.
roll_shadow) alongside the old version — zero module-code changes; the shadow is a layer the bot owner enables in config:影子实例以独立 owner(如
roll_shadow)与旧版并存,模块代码零改动——影子是主人在配置里启用的一层:Behavior / 行为说明:
shadowmarker; the shadow is excluded from the dependency graph (module.calland dependency resolution still point to v1) / scope 准入后复制投递并带shadow标记;影子不参与生态依赖图(module.call与依赖解析仍指向 v1,避免半成品被依赖)SendDSL and Api calls are intercepted and recorded, never actually sent (reusing the outbound rule wrapper) — no duplicate replies / 影子的 Send DSL 与 Api 调用全部拦截记录、不真正发出(复用出站规则包装层)——不产生重复回复trace_id; a failed promote rolls back to v1 automatically / v1 实际发送(transcript)vs v2 意向发送(影子账本)按trace_id对齐;promote 失败自动回滚 v1Promote CLI / 转正命令:
Feedback / 十三、反馈
Reply by number. Direction-level disagreements are especially welcome — if you disagree, please describe your use case.
按编号回复即可,方向级反对尤其欢迎——反对时请描述你的使用场景。
options=declaration the right fit? / 参数与选项类型够用吗?字典式options=声明是否合意?@dataclass+field(metadata=...)) or standaloneField()descriptors? / ORM 改为内置交付(原独立包)——你的意见?最期待哪个能力:增删改查 / 自动迁移 / 关系映射?声明风格偏好:配置类同款(@dataclass+field(metadata=...)) 还是独立Field()描述符?command_groupregistrar sugar, CLI config overrides — both P2 / 优先级排序有不同意见吗?2.9 还漏了什么?未入主线的候选:command_group注册器语法糖、CLI 式配置覆盖——均为 P2)Falseas the middleware veto signal sufficient for your firewall / rate-limit scenarios? / 防火墙/限流场景下,显式返回False作为否决信号是否够用?cooldown_reply" the right default for cooldown hits? And is"5/minute"the right rate-limit syntax? / 冷却命中"默认静默 + 可选回复文案"是否合意?"5/minute"限流语法是否合适?module.shadow("roll")) over theroll_shadowowner naming? Is "read the real database, write to the overlay" the right storage semantics? / 影子模块:独立子注册表(module.shadow("roll"))与roll_shadow命名孰优?存储「读真库、写覆盖层」口径是否合适?ErisPulse Core Team — 2026-09-13 发布 / 2026-09-14 修订 / 2026-09-23 修订(交付状态与后续候选)/ 2026-09-24 修订(结构拆分:交付状态移至进度评论;
usage_limit=并入治理章节;新增方向 10/11:模块重载完备性、影子模块与灰度转正)All reactions