My POC shows that this is indeed true, probably by design (I guess it makes sense, sort of).
Lightning-console apps consider every LOADED tab in scope of an application event. To further complicate this behavior, if more than one record tab is LOADED, then you refresh the browser, only the current record tab is back in scope of an application event. I think this is because the second tab hasn't bootstrapped into the one.app namespace yet.
FYI, I'm using my own service component framework (https://github.com/tsalb/sfdc-lightning-service-components) to fire these events, but the underlying application event firing mechanism is the same, I just have method wrappers to help fire generic ones.
Place both on same Lightning Record Page in Lightning-console app
AppEventFire.cmp
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId">
<c:EventService aura:id="eventService"/>
<lightning:button label="Fire App Event" onclick="{! c.handleFireAppEventClick }"/>
</aura:component>
AppEventFireController.js
({
handleFireAppEventClick : function(component, event, helper) {
var eventService = component.find("eventService");
eventService.fireAppEvent("TEST_RECORD_EVENT_FIRE");
}
})
AppEventListener.cmp
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId">
<aura:handler event="c:ServiceAppEvent" action="{! c.handleApplicationEvent }"/>
<aura:attribute name="record" type="Object"/>
<aura:attribute name="simpleRecord" type="Object"/>
<aura:attribute name="recordError" type="String"/>
<force:recordData aura:id="recordHandler"
recordId="{!v.recordId}"
layoutType="FULL"
targetRecord="{!v.record}"
targetFields="{!v.simpleRecord}"
targetError="{!v.recordError}"
mode="EDIT"
/>
{! v.simpleRecord.AppEventCount__c }
</aura:component>
AppEventListenerController.js
({
handleApplicationEvent : function(component, event, helper) {
var params = event.getParams();
switch(params.appEventKey) {
case "TEST_RECORD_EVENT_FIRE":
var currentCount = component.get("v.simpleRecord.AppEventCount__c");
currentCount++;
component.set("v.simpleRecord.AppEventCount__c", currentCount);
component.find("recordHandler").saveRecord($A.getCallback(function(saveResult) {
if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
component.find("recordHandler").reloadRecord();
}
}));
break;
}
},
})
Then open up two records within the same Lightning-console app, fully load both (so that the fire.cmp and listener.cmp exist, are rendered). You'll see that if you fully load two Lightning-console app tabs, then click the button from either one, both will receive it. I'm writing to server to verify that these application events persist and it's not just a trick of browser / component memory.
P.S. I've added what I'm calling a Record Event to my framework which deals with this very specific issue, very specifically inside lightning-console apps. I'll update my framework repo when I get some time.