Conversation
…207) Extend the disclosure hook so it fires identically for kernel-origin and proactive/timer/headless dispatches as for worker-requested ones. Per spec #204 story 7 there must be no second, ungated path for autonomous outbound content. What changed: - Parameterize the shared mediation entrypoint (`mediate_and_dispatch_action_with_attribution_and_token`) on `ActionOrigin` and thread it into the single `gate()` call, replacing the hardcoded `ActionOrigin::Shell`. Every existing wrapper keeps passing `Shell`. - Add the blessed kernel-origin dispatch entry `mediate_and_dispatch_action_kernel_origin` (dormant `#[allow(dead_code)]`, mirroring `escalation::resolve_grant_for_thread`): the single path any future proactive/autonomous producer routes rated outbound content through, so no one hand-rolls another connector call. The disclosure hook is unconditional on the action's catalog `egress_class` after Allow, so it runs identically regardless of origin. - Production-entering tests (drive the real mediation entrypoints): a rated `email.send` with an uncovered disclosure policy blocks and raises `OwnerQuestion` for kernel-origin, worker-origin, and the proactive headless lane — all identical. Plus an invariant proving the one hand-rolled kernel-origin path (`notify_owner_with_digest`) carries no gated egress because `owner.notify` stays unrated and owner-facing. - Register CLAIM-43 in docs/threat-claims.md. - Repair a pre-existing concurrent-merge break: #224 added `BriefcaseSection.origin`; #206's messaging test predated it and no longer compiled. No new openspec change (retired for new work per DIRECTION.md); the guarantee is recorded via CLAIM-43. Closes #207 Implementation-notes summary: 1. Deviations: 4 (dropped CodeRabbit notify-refusal guard as an unreachable second path; skipped OpenSpec change per DIRECTION.md; used real email.send over a synthetic action because the disclosure core resolves egress from the canonical catalog; dormant #[allow(dead_code)] kernel entry rather than #[cfg(test)]). 2. Most likely to be revisited: the kernel-origin entry's dormant #[allow(dead_code)] — drops when a real kernel-origin rated-dispatch producer lands. 3. Edge cases: concurrent-merge break (BriefcaseSection.origin) repaired; route_escalation delivers the owner Telegram message before appending the owner.question audit, so tests mock it. 4. No irreversible/scope-changing decisions; no blocking questions. 5. Read first: crates/openspine-kernel/src/api/actions.rs (origin param + enforce_rated_disclosure) and disclosure/core.rs (trusted_egress_class uses the canonical catalog).
|
Warning Review limit reached
Next review available in: 27 minutes Limit details: You’ve used the included review currently available. You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?Wait for the limit to reset, then comment An organization admin can change what happens after included review limits in Billing. How do review limits work?CodeRabbit enforces per-developer PR review limits within each organization. For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
What & why
Final disclosure ticket (#207, spec #204 story 7). The external-egress disclosure hook must fire identically regardless of dispatch origin — worker-requested, kernel-origin, or the proactive headless lane with no principal present. There must be no second, ungated path for autonomous outbound content.
Root cause: the shared mediation entrypoint hardcoded
ActionOrigin::Shellin its singlegate()call, so the kernel-origin capability of the mediation body was untested and no blessed kernel-origin dispatch entry existed. The disclosure hook itself was already origin-independent (it triggers purely on the catalogegress_classafter Allow).Changes
mediate_and_dispatch_action_with_attribution_and_tokenonActionOrigin, threaded into the singlegate()call. All existing wrappers keep passingShell(no behavior change).mediate_and_dispatch_action_kernel_origin— dormant#[allow(dead_code)], mirroring the repo'sescalation::resolve_grant_for_threadidiom. It's the one path a future proactive/autonomous producer routes rated outbound content through, instead of hand-rolling a connector call. The disclosure hook is unconditional onegress_classafter Allow, so it runs identically for any origin.email.sendwith an uncovered disclosure policy blocks and raisesOwnerQuestionfor kernel-origin, worker-origin, and the proactive headless lane — all identical. Plus an invariant proving the one hand-rolled kernel-origin path (notify_owner_with_digest) carries no gated egress becauseowner.notifystays unrated and owner-facing (criterion 2: no ungated path).docs/threat-claims.md.BriefcaseSection.origin; Wire email.send into the generalized disclosure hook end-to-end #206's messaging test predated it and no longer compiled.Design notes
RatedActionRefusedguard onnotify_owner_with_digest(proposed by the auto-generated plan): that path only dispatchesowner.notify(owner-facing, unrated), which the disclosure hook does not govern. A bespoke refusal would be a second divergent behavior (refuse ≠ spec-mandated OwnerQuestion) with an unreachable trigger. Expressed as an invariant test instead.DIRECTION.md; the guarantee is recorded via CLAIM-43.ActionOrigin::Shell; the claim/tests scope themselves to what's directly exercised (headless lane) and do not overclaim a dedicated timer test.Verification
./scripts/check.shgreen (fmt, clippy-D warnings, fullcargo test --workspace, file-size, claims, omp-ceremony,openspec validate --all --strict).Closes #207
Implementation-notes summary
email.sendover a synthetic action because the disclosure core resolves egress from the canonical catalog; dormant#[allow(dead_code)]kernel entry rather than#[cfg(test)]).#[allow(dead_code)]— drops when a real kernel-origin rated-dispatch producer lands.BriefcaseSection.origin) repaired;route_escalationdelivers the owner Telegram message before appending theowner.questionaudit, so tests mock it.crates/openspine-kernel/src/api/actions.rs(origin param +enforce_rated_disclosure) anddisclosure/core.rs(trusted_egress_classuses the canonical catalog).Summary by cubic
Makes external-egress disclosure enforcement origin-symmetric so rated outbound content is mediated the same for worker-origin, kernel-origin, and headless dispatch. Previously the shared mediation entrypoint hardcoded
ActionOrigin::Shell, leaving kernel-origin without a blessed path and risking an ungated route.mediate_and_dispatch_action_with_attribution_and_tokenwithActionOrigin; existing wrappers still passShell(no behavior change).mediate_and_dispatch_action_kernel_originas the single blessed kernel-origin dispatch entry for future proactive/autonomous producers; currently dormant.email.sendblocks and raisesOwnerQuestionidentically for worker, kernel, and headless; assertsowner.notifyremains unrated and owner-facing (no gated egress).BriefcaseSection.originin a test. No OpenSpec change; no migration actions.Written for commit 45ba784. Summary will update on new commits.