- conforms_to::[[Observation Form Contract]]
- has_epistemic_status::[[Empirical Observation]]
- in_practice_domain::[[eOS Continuum]]
- authored_by::[[Christopher Allen]]
- has_lifecycle::[[Seed Stage]]↗
- has_curation::[[Working Draft]]↗
An Admin-Capability-Holding User Can Kick from a Chat Room
Claim
In the eOS-Harness MVA running against DGD 1.7.9 plus the eOSContinuum/eOS-kernellib feature/cohesive-lift branch carrying the kernel-layer cohesive lift (Vault + Schema + XML + Index + Merry + property-change dispatcher), an admin verb in an application-tier daemon that calls a private capability-check helper at the public-LFUN entry accepts the call when the actor holds an admin-token covering the target room and action. The dispatch shape is: a boot-time test driver clones three users and one room, attaches a per-room "kick" admin-token to one user via admin->grant_admin(nil, holder, room, ({ "kick" })), then calls admin->kick(holder, target, room). The capability check walks the holder's chat-user.admin-tokens list, matches the token by query_room() and query_actions(), and returns silently; the verb proceeds by calling chat::leave_room(target, room), which removes the target from chat-room.member-list and removes the room from the target's chat-user.room-subscriptions. The test driver asserts both removals and writes a CAP-ACCEPT OK sentinel to its result file. The same LFUN that rejected the no-token actor in the paired Observation accepts the token-holding actor; the gate is parameterized on the actor's token holdings, not on the caller's program or the LFUN's name.
Grounds
This is an Empirical Observation. The grounds are a captured cold-boot smoke run 2026-05-27 against the live MVA demonstration instance with examples/chat-app/ (deployed from the eOSContinuum/eOS-kernellib examples/chat-app/) overlaid at the isolated runtime staging tree's src/usr/Chat/.
Setup (verifiable from repo state):
- Driver: DGD 1.7.9 built from
dworkin/dgd; binary symlinked at the isolated runtime staging tree'sbin/dgd. - Kernel layer:
eOSContinuum/eOS-kernellibonfeature/cohesive-liftat HEAD456716c(the chat-app commit; built atop kernel-layer baselineecb4e58). - Application layer:
examples/chat-app/(this commit's deliverable), deployed into the isolated runtime staging tree atsrc/usr/Chat/. - Runtime config: the instance config, telnet
127.0.0.1:8023, binary/HTTP127.0.0.1:8080, the isolated runtime staging tree layout.
Load-bearing source (the capability check in examples/chat-app/sys/admin.c):
private
void _check_admin_token(object actor, object room, string action)
{
mixed *tokens;
mixed token;
int i, sz;
if (!actor) {
error("admin: nil actor for " + action);
}
tokens = actor->query_admin_tokens();
sz = sizeof(tokens);
for (i = 0; i < sz; i++) {
token = tokens[i];
if (!token) continue;
if (token->query_room() != room && token->query_room() != nil) {
continue;
}
if (member(action, token->query_actions())) {
return;
}
}
error("admin: actor " + ... + " not authorized for " + action + " ...");
}
void kick(object actor, object target, object room)
{
_check_admin_token(actor, room, "kick");
if (!target) error("kick: nil target");
if (!room) error("kick: nil room");
CHAT_DAEMON->leave_room(target, room);
}
Boot sequence: a clean cold boot against the isolated runtime staging tree, with examples/chat-app/ materialized at src/usr/Chat/ and the instance config loaded, reaching ** Initialization complete. in under one second.
** DGD 1.7.9
** Initializing...
** Initialization complete.
The Chat domain's initd compiled obj/room, obj/user, data/admin_token, sys/chat, sys/admin, and sys/test; the deferred call_out("setup_and_run", 0) from sys/test::create() fired after every per-domain initd had returned.
Phase 2 smoke transcript (the load-bearing portion of the sentinel result log after the cold-boot completes):
ChatApp:test: starting
ChatApp:test: CAP-REJECT OK
ChatApp:test: CAP-ACCEPT OK
CAP-ACCEPT OK writes to the sentinel file only when:
grant_admin(nil, carol, room_a, ({ "kick" }))returns a non-nil token (the LWO instantiation and attach-to-subject path succeeded).admin->kick(carol, alice, room_a)returns without throwing (the capability check matched).member(alice, room_a->query_members())returns false (the kick removed alice from the room's member list).member(room_a, alice->query_subscriptions())returns false (the kick removed the room from alice's subscriptions).
All four assertions ran inside catch{} blocks. The boot log carries no [caught] annotation for the kick verb during phase 2 (the boot log's [caught] annotations are limited to phase 1's deliberate rejection); the verb completed normally.
Process identity check: a single DGD process served all four assertions in one boot. The boot log records no ** System halted. entry between phases. No statedump was invoked. No admin_console session was opened. The runtime instance carrying the assertions is the same one initialized at ** Initialization complete..
What the evidence establishes:
- A capability-token LWO attached to a user's
chat-user.admin-tokensproperty carries enough information (subject, room, actions) to gate a verb at the application-daemon level. - The capability check is parameterized on the actor's holdings; the same LFUN that rejects a no-token actor in the paired Observation accepts a token-holding actor without any code path change.
- The check is enforced at the public-LFUN entry, before any state mutation. The verb's body (which calls
chat::leave_room) only fires after the check returns silently. - The capability mechanism composes with the runtime's atomicity primitive: the verb's body either fully runs (after acceptance) or does not run (after rejection). There is no half-completed kick state observable in either case.
What the evidence does not establish:
- Property-layer enforcement against direct writes. The capability check sits at the LFUN entry, not at the property-storage layer. A caller with a handle to the room object could still write to
chat-room.member-listdirectly viaroom->set_property(...). The MVA-scope decision inexamples/chat-app/is convention-level capability separation (LFUN-only gating); a stricter property-write-time gate is a future workstream's scope, noted separately formerry:on:*writes. - Token-issuance authority.
grant_adminis itself capability-gated when called with a non-nilgrantor, but the bootstrap path withgrantor=nilis gated only by the caller's domain (the Chat domain itself). A real deployment would replace thenil-grantor path with a sealed bootstrap token or an out-of-band issuance flow. - Cross-room admin behavior. The smoke exercises one room. A token explicitly scoped to room A applied to a kick in room B is rejected by the room-comparison branch in
_check_admin_token; the smoke does not exercise this. A future phase that creates multiple rooms with per-room admin tokens would extend the empirical claim. - Token revocation. No
revoke_adminLFUN was exercised. A token attached to a user persists until the user is destructed; a revocation surface and a re-check on each verb invocation against an authoritative live registry is a future workstream's scope. - Persistence. The chat application has not yet been exercised through a statedump-restore cycle. A future persistence-demonstration phase will demonstrate that token holdings (and the rest of the chat state) survive a snapshot.
What Would Revise It
- A demonstration that the capability check holds under direct LFUN bypass. A future probe that attempts to call
kickviacall_other(ADMIN_DAEMON, "kick", regular_actor, target, room)from an attacker object in a different domain, asserting that the cross-domain access discipline plus the capability check together reject the call, would extend the claim from "verb-entry gate holds against the test driver" to "verb-entry gate holds against arbitrary callers in the global-access surface". - A demonstration that the capability check holds against the property-write bypass path. A probe that writes directly to
chat-room.member-listfrom a no-token caller, observing that the membership mutates (because the property-write path is not gated), would document the MVA-scope boundary explicitly. The contrapositive: if the property-write path were gated and rejected the direct write, the MVA-scope claim would need amendment. - A token-scope mismatch probe. A probe that creates two rooms, grants the actor a token scoped to room A only, then attempts
kick(actor, target, room_B), asserting that the room-comparison branch in_check_admin_tokenrejects the call, would extend the empirical claim from "matching token accepts" to "matching token accepts AND non-matching token rejects". - A multi-action probe. A probe that grants a token with actions
({ "kick" })(no "ban") then attemptsban(actor, target, room), asserting that the action-comparison branch rejects the call, would extend the empirical claim from single-action to multi-action capability. - Concurrent dispatch under capability check. The empirical sequence uses sequential boot-time calls. A concurrent-dispatch probe (multiple simultaneous
kickrequests against the same room, with one holder and one non-holder interleaved) would extend the claim from "sequential capability gate holds" to "concurrent capability gate holds". - A DGD or eOS-kernellib upgrade that changes LFUN-entry semantics or LWO instantiation cost. The current evidence rests on DGD 1.7.9 plus
feature/cohesive-liftHEAD456716c. A future runtime release that changes the cost or semantics ofnew_objecton LWOs, or changes howprevious_program()resolves at private-LFUN entry, would invalidate the snapshot claim; the pinning is part of the grounds.
Sources
examples/chat-app/sys/admin.c(ineOS-kernellib feature/cohesive-lift) -- the application-daemon source whosekickLFUN is the load-bearing verb. The_check_admin_tokenhelper is the capability check; the verb body callsCHAT_DAEMON->leave_roomafter the check returns.examples/chat-app/data/admin_token.c-- the capability LWO. Carries (grantor, subject, room, granted_at, actions); created bynew_object(TOKEN_LWO)insidegrant_admin.examples/chat-app/obj/room.c-- the Room clonable. Property-storage backed;query_membersexposes the member list;remove_memberdoes the subtractive array update onchat-room.member-list.examples/chat-app/obj/user.c-- the User clonable. Property-storage backed;query_admin_tokensexposes the LWO list;add_admin_tokenappends.examples/chat-app/sys/chat.c-- the chat dispatcher.leave_roomremoves the user from the room's member list and removes the room from the user's subscriptions.examples/chat-app/sys/test.c-- the boot-time test driver. Phase 2 grants carol a kick token, callskick(carol, alice, room_a), and asserts the two removals.examples/chat-app/README.md-- the deployment + verify recipe.docs/chat-applications.md(ineOS-kernellib feature/cohesive-lift) -- the walkthrough doc; the "Phase 2 -- CAP-ACCEPT" section quotes the load-bearing capability check shape.- The isolated runtime staging tree's
src/usr/Chat/data/test-result.log-- the sentinel file the test driver writes to. CarriesCAP-ACCEPT OKafter a clean cold-boot. - The instance config (telnet 8023, binary/HTTP 8080, the isolated runtime staging tree's source directory).
src/usr/Merry/sys/merry.c(ineOS-kernellib) -- the_check_registrarcapability gate whose shape_check_admin_tokenmirrors; the analogous private-helper-after-public-LFUN-capture pattern.
Relations
-
conforms_to::[[Observation Form Contract]]
- Carries
has_epistemic_status::[[Empirical Observation]], names the measurement (one cold-boot smoke run with two boundary assertions in the same phase), states the limits of the measurement (LFUN-entry gate only; property-write bypass not closed; single-room scope; sequential dispatch), and lists concrete revision conditions.
- Carries
-
informs_downstream::[[Capability Boundaries Are Runtime-Enforced, Not Policy-Checked]]
- The capability-separation Conviction's "What It Asks" anticipates exactly this kind of evidence: a capability-token mechanism gating a verb at runtime entry, with the same verb accepting and rejecting based on the actor's holdings rather than the application code remembering to check. This Observation is the positive half; the paired negative shows the same gate's rejection path.
-
grounded_in::[[Conviction Form Contract]]
- The capability mechanism inherits the same "runtime, not policy" stance the Conviction names. The application's
_check_admin_tokenis a runtime check (it fires unconditionally before any verb body executes), not a policy hint (the verb body cannot opt out of the check).
- The capability mechanism inherits the same "runtime, not policy" stance the Conviction names. The application's
-
contrasts_with::[[A Regular User Cannot Kick from a Chat Room]]
- The negative-case peer Observation. The two together cover the with-token and without-token cases of the same kick LFUN. Reading one without the other gives an incomplete picture: the negative case alone shows rejection but not what acceptance looks like; this case alone shows acceptance but not what the rejection signal carries. The paired sentinels (
CAP-REJECT OKandCAP-ACCEPT OK) land in the same result file across the same cold-boot.
- The negative-case peer Observation. The two together cover the with-token and without-token cases of the same kick LFUN. Reading one without the other gives an incomplete picture: the negative case alone shows rejection but not what acceptance looks like; this case alone shows acceptance but not what the rejection signal carries. The paired sentinels (