Skip to content

feat(permissions): lockCaller that pins the CALLING module from inside a service leaf that accepts a callback #477

Closed

Description

@Shinrai

Problem

self.slothlet.lockCaller(fn) captures getCallerIdentity().currentWrapper. A service leaf that accepts a callback — e.g. a host scheduler leaf every(interval, fn) mounted via object-form api.add — can only pin itself with it: inside the leaf, the current wrapper is the leaf, and the module that called the leaf is callerWrapper. So callbacks handed to service leaves run as the service, and identity-scoped calls inside them (self.store.open-style partitioning, permission rules keyed by caller, surface grants) bind the service's identity instead of the calling module's.

Today every consumer must remember to pass self.slothlet.lockCaller(fn) itself, which is easy to miss and fails quietly (the callback just runs as the wrong module).

Proposal

A variant that captures the caller of the current leaf rather than the leaf itself, e.g. self.slothlet.lockCaller(fn, { to: "caller" }) or self.slothlet.lockCaller.caller(fn), resolving the identity the same way metadata.caller() does (callerWrapper). Permission-gated like lockCaller (built-in allowed). The same gap applies to event.on / hook.on when a service leaf subscribes on a caller's behalf — they could accept the same option.

Downstream

@cldmv/rummage ext-host: command handlers and event listeners are now pinned at registration via lockCaller (correct), but host service leaves that take callbacks (self.host.scheduler.every/once) cannot pin the calling extension and currently document "pass self.slothlet.lockCaller(fn)".

Activity

  1. added
    semver: minorThis release adds new functionality in a backwards-compatible way
    priority: mediumShould be addressed in the normal course of development
    type: feature requestA request to add new functionality that does not currently exist
    area: coreTouches core library / runtime source code
    status: not startedNot implemented yet — no code exists for this
    on Sep 27, 2026
  2. Shinrai commented on Sep 28, 2026

    @Shinrai
    ContributorAuthor

    Folding in #489, which asks for the same capability from another consumer. Requirements it adds on top of this issue:

    • Permission-gated: letting a leaf act as its caller is a privilege, so it needs an explicit grant, the same kind of rule as metadata.caller, rather than being allowed by default like plain lockCaller.
    • Composes with principals (feat(permissions): named, module-owned principals — async-resolved identity facts for sync conditions #459): the pinned caller identity should resolve principals the same way a direct call from that caller would.
    • Immutable after capture: the identity is captured at call time and can't be changed afterwards, with the same guarantees as today's lockCaller.
    • Second real case: rummage's deadline extension builds a reminder engine per consumer via self.deadline.engine(...) and ticks them all from one scheduled job. The ticks run as the deadline extension, so owner attribution is carried as a payload field (owner, from metadata.caller()) instead of by caller identity.

    Option name is still open: #489 proposed lockCaller(fn, { as: "caller" }); this issue proposed { to: "caller" } or lockCaller.caller(fn).

  3. added
    status: in progressPartially implemented — actively being built
    status: implementedBuilt and deployed, but not yet fully tested/verified
    and removed
    status: not startedNot implemented yet — no code exists for this
    status: in progressPartially implemented — actively being built
    on Sep 29, 2026
  4. Shinrai commented on Sep 29, 2026

    @Shinrai
    ContributorAuthor

    Landed on next in #516 (067a8229) as self.slothlet.lockCaller.caller(fn), gated by a built-in deny the host grants. Ships in 3.22.0; this closes when it reaches master.

  5. cldmv-bot commented on Oct 3, 2026

    @cldmv-bot
    Contributor

    Closed in v3.22.0 — resolved by #516.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: coreTouches core library / runtime source codepriority: mediumShould be addressed in the normal course of developmentsemver: minorThis release adds new functionality in a backwards-compatible waystatus: implementedBuilt and deployed, but not yet fully tested/verifiedtype: feature requestA request to add new functionality that does not currently exist

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions