Repository navigation
feat(sync): daemon-layer auto-grant on subscription (killswitch-gated) - #122
Merged
Merged
Conversation
added 2 commits
October 15, 2026 19:35
Implements the approved "守护层自动签发" proposal: the daemon evaluates the
policy graph and issues grants through the SAME chain as manual approval
(Mebular.grantNamespaces) for devices that are 图上在册 (subscription =
membership, M1) ∧ not revoked ∧ without an effective grant — the "批准" step
becomes automatic while the policy engine (derivation / invariants / storage /
sync hot path) stays untouched.
- src/sync/autoGrant.ts (new): pure evaluator. Rule chain: trusted (implicit
via snapshot trust root) →【红线】not revoked (snapshot.revoked hard
precondition; R-d recovery semantics mean an adopted grant CLEARS
revocation, so auto-issue must never target revoked devices) → subscription
declared (active membership) → no effective grant (idempotent) → skip self
(rejoin semantics frozen this round) → issuer qualification (R-a local
pre-check: bootstrap issuer or self authorized). Red-line hardening per
product: re-check revocation per subject right before issuing
(confirmNotRevoked) to minimize the snapshot→append race window.
- src/mebular.ts: sync.autoGrant config ({enabled, intervalMs}; library
default OFF, daemon default ON — antiEntropy-shaped) + lifecycle wiring:
first eval (next tick, init-safe) + periodic sweep (30s) + debounced eval
on sync-completed. Trigger source note: events-applied does NOT fire for
__policy__ records (applyRemoteEvent only materializes node/edge/tag
types), so the debounce hooks sync-completed instead — zero SyncManager
changes (scope红线). shutdown/rollback stop the evaluator.
- packages/mcp: serve defaults autoGrant on (config.mjs createMebular
fallback + init-generated config.json), kill-switch via
sync.autoGrant.enabled=false in config.json.
- tests/sync/auto-grant.test.ts (new, +16): rule chain, red line (incl.
confirm-veto), race-ordering semantics (grant→revoke re-revokes; revoke
→grant clears — why the precondition exists), untrusted records, self/
qualification/idempotence/multi-supplier, facade E2E (subscribe → auto
release → data; block → subscribe → denied; event wiring; killswitch).
- scripts/accept-auto-grant.mjs (new): real-daemon adversarial acceptance,
15/15 — red line first, note='auto-grant' evidence, idempotence,
killswitch, mixed-version neutral + CLI fallback.
Pre-existing finding (NOT introduced here, reproduced on origin/main, NOT
fixed per scope discipline): delegated-daemon → root-daemon device-authored
events never land (peer-id keying asymmetry suspected; verify-daemon-cluster
only covers A→B). Acceptance therefore pairs real supplier daemons with
in-process subscriber facades (real libp2p/signing/storage) — the direction
proven working by probes. Details in the PR body.
npm test 1150 → 1166 (+16, all green); verify:daemon 43/44 (baseline-equal);
check:docs/surface-parity/cleanliness/deps green; lint clean.
Owner
Author
真机对抗验收原始输出(
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
守护层自动签发(订阅驱动授权)· 批准版实施
按已批准提案(
core-autosign-proposal.md)实现,范围=批准版:core 引擎(策略推导/不变量/存储/同步热路径)零改动;不含 hello 登记表(产品决定第一轮 core 零触碰,legacy 域维持中性态+CLI 兜底)。改动面(
git diff --stat自证,6 文件 +768/-1)src/sync/autoGrant.ts(新)src/mebular.tssync.autoGrant配置(库默认关/守护默认开,照 antiEntropy 形状)+ 生命周期(首评/周期 30s/会话结束去抖 2s/关停)+ 吊销集合只读转发packages/mcp/bin/mebular.mjs+packages/mcp/src/config.mjssync.autoGrant.enabled:falsetests/sync/auto-grant.test.ts(新,+16)scripts/accept-auto-grant.mjs(新)红线加固(产品特别要求,全部落地)
snapshot().revoked排除)——R-d 恢复语义(grantPolicy.ts:436-437:被采纳 grant 清除吊销)决定不查吊销=屏蔽崩塌;confirmNotRevoked,新鲜推导)——竞态窗口压到最小;grant→device_revoke重新吊销 ✓、device_revoke→grant清除吊销(红线存在的原因)✓。验收
node scripts/accept-auto-grant.mjs,双守护 loopback 沙箱):[]、屏蔽后新数据不到达;{"subject":"device-C","namespaces":["work"],"note":"auto-grant: subscription-driven"};幂等(恰一条);note字段(collectPolicy已透出,admin 视图可见/可按 note 过滤)。verify-console.mjs:578(rejoin 409)未受影响(评估器跳过 self,rejoin 语义冻结;全量套件含该断言为绿)。实施中发现:delegated 守护 → root 守护的设备自签事件(membership 等)永不落图。
origin/main(9505dbc7)上同一脚本完整复现:C 视 A 的 peerId 为拨号地址里的 libp2p id(12D3KooW…),A 视 C 为握手呈现的 hex 摘要——疑似对端键控非对称使 nudge/常驻会话静默失配;verify-daemon-cluster只覆盖 A→B 方向故从未暴露。探针实证:facade↔daemon 三个组合均正常,仅 daemon×daemon 此方向失败。修复需动 SyncManager/P2PNode 连接键控(超出本轮批准文件清单),请主控/产品单独立项。本 PR 的真机验收因此采用「真实守护供给端 × in-process 订阅端门面」(真 libp2p/签名/存储;探针已证该方向可用)。设计偏差说明(提案 → 实现)
事件触发源由提案的
events-applied('__policy__')改为sync-completed去抖:events-applied只对物化进图存储的事件计数,__policy__记录不经applyRemoteEvent物化(实测证实不发),在不碰 SyncManager 的约束下sync-completed是唯一可靠触发点(membership 只能经同步会话到达)。时延语义不变(会话结束 +2s)。待 CI 五项绿后由用户合并(我不合并)。