Skip to content

Context Clearing#1379

Merged
kemerava merged 24 commits intofinos:1197-context-clearingfrom
kemerava:feature/context-clearing
Jul 29, 2025
Merged

Context Clearing#1379
kemerava merged 24 commits intofinos:1197-context-clearingfrom
kemerava:feature/context-clearing

Conversation

@kemerava
Copy link
Contributor

Closes #1197

Adding context cleaning

@michael-bowen-sc

@kemerava kemerava requested a review from a team as a code owner September 27, 2024 18:37
@netlify
Copy link

netlify bot commented Sep 27, 2024

Deploy Preview for fdc3 ready!

Name Link
🔨 Latest commit a7e5c4b
🔍 Latest deploy log https://app.netlify.com/projects/fdc3/deploys/6883d673a522e200081a074a
😎 Deploy Preview https://deploy-preview-1379.preview-fdc3.finos.org
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

broadcast(context: Context): Promise<void>;
getCurrentContext(contextType?: string): Promise<Context|null>;
addContextListener(contextType: string | null, handler: ContextHandler): Promise<Listener>;
clearContext(contextType?: string): Promise<void>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should require an explicit null argument (contextType: string | null) to clear all types - which would match addContectListener or stick with this (matching getCurrentContext). Either works of course.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me it makes sense to keep it closer to getCurrentContext, because they seem most related to me, but happy to hear any thoughts/suggestions.

Copy link
Contributor

@kriswest kriswest Oct 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a historical reason for addContextListener having an explicit null argument, the contextType argument was originally optional so the handler argument could be either first or second (when a type was specified). This was NOT good in practice so we moved to an explicit null argument and deprecated the single argument override:
https://fdc3.finos.org/docs/2.0/api/ref/DesktopAgent#addcontextlistener-deprecated

We don't have that problem here, so I agree its fine as is (matching getCurrentContext).

Copy link
Contributor

@kriswest kriswest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Many thanks for taking this on @kemerava.

Could you add an entry to the CHANGLOG.md file please.

I think we should keep this open until after fdc3 for the web (#1191) is merged, when we will need to add schemas for a request and response message. The same may be needed in the bridging (the fdc3.nothing ewill propagate through normal broadcast messages, but I think this will need a specific message to indicate it happened through the clearContextAPI call).

@kriswest kriswest added this to the 2.3 candidates milestone Oct 1, 2024
kemerava and others added 2 commits October 4, 2024 08:46
Copy link
Contributor

@kriswest kriswest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - although we could do with an example of listening for cleared context somewhere.

Holding approval until after fdc3-for-web is merged as we'll then need to add schemas to support it there. Bridging schemas are also needed, those should be added before this is merged.

Many thanks for the contribution @kemerava, much appreciated.

@kemerava
Copy link
Contributor Author

@kriswest could you please take a look at the conformance tests that I added? Thanks

Copy link
Contributor

@kriswest kriswest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding the conformance test cases! I think we'llneed a couple f additional cases that look the effect on user channels.

- `ACContextHistoryLast`: In step 5. **A** retrieves the _untyped_ current context of the channel via `const currentContext = await testChannel.getCurrentContext()`. Ensure that A receives only the very last broadcast context item _of any type_.
- `ACClearHistorySpecificContext`: Perform the above test, except after step 3 clear context with `await testChannel.clearContext('fdc3.instrument')`. Ensure that in step 5 nothing is received for `const instrument = await testChannel.getCurrentContext('fdc3.instrument')` and context is received successfully for `const instrument = await testChannel.getCurrentContext('fdc3.contact')`
- `ACClearHistoryAllContexts`: Perform the above test, except after step 3 clear context with `await testChannel.clearContext('fdc3.nothing')`. Ensure that in step 5 nothing is received for `const instrument = await testChannel.getCurrentContext('fdc3.instrument')` and for `const instrument = await testChannel.getCurrentContext('fdc3.contact')`
- `ACClearHistoryAllContextsSubscribedToNothing`: Perform the above test, except after step 3 clear context with `await testChannel.clearContext('fdc3.nothing')` and in step 4 call `await testChannel.addContextListener("fdc3.nothing", handler)` instead. Ensure that after clearing context, the handler is called.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few thoughts on this case:

  • I think you want to clear fdc3.instrument or all types (null) rather than fdc3.nothing
  • As written, the nothing handler is added after calling clear, in that case it won't receive anything on an app channel. The handler needs to be in place before the clear.
  • I think this needs to be 2 cases, one for clearing all types and another for a specific type that confirms the other is not affected and that the fdc3.nothing quotes the correct type.
  • Finally, I think we need at least one case that checks the behavior of user channele- you'll work with the channel as an app channel to clear it (either retrrieving it by name, via getUserChannels, or getCUrrentChannel) but we should also confirm that it gets the fdc3.nothing broadcast and that it doesn't retain the cleared context.

@kriswest kriswest requested review from a team and kriswest April 17, 2025 15:32
@kriswest
Copy link
Contributor

/netlify

@kriswest
Copy link
Contributor

@kemerava, @robmoffat and I were talking about this recently and wondering if we should rethink the fdc3.nothing use and instead go with events... We could bring addEventListener to Channel (currently only in PrivateChannel and allow aps to listen for context clearing events (on the DA for the current user channel on the channel object for specific channels). I think the fdc3.nothing use is probably the weakest or most awkward part of the proposal (particularly if someone broadcasts fdc3.nothing from an app).

WDYT?

@kemerava
Copy link
Contributor Author

kemerava commented May 8, 2025

@kemerava, @robmoffat and I were talking about this recently and wondering if we should rethink the fdc3.nothing use and instead go with events... We could bring addEventListener to Channel (currently only in PrivateChannel and allow aps to listen for context clearing events (on the DA for the current user channel on the channel object for specific channels). I think the fdc3.nothing use is probably the weakest or most awkward part of the proposal (particularly if someone broadcasts fdc3.nothing from an app).

WDYT?

@kriswest @robmoffat updated based on what I understood the logic would be. Please let me know if I need to change something else or if I misunderstood your suggestion

I see I still have to fix some of the build errors too

@kriswest kriswest requested review from a team, Roaders and bingenito July 9, 2025 13:25
@bingenito bingenito requested a review from Copilot July 9, 2025 13:38
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

Adds a new clearContext API to channels, updates schemas and reference docs to support context-cleared events, and extends conformance tests for the new behavior.

  • Introduce clearContext method and contextCleared event in Channel API and implementation
  • Update JSON schemas and agent protocol to include clearContext request/response
  • Enhance documentation and conformance tests for context-clearing scenarios

Reviewed Changes

Copilot reviewed 14 out of 15 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
website/versioned_docs/version-2.0/api/conformance/App-Channel-Tests.md Add versioned tests for clearing specific/all contexts
website/static/schemas/2.2/api/agentResponse.schema.json Register clearContextResponse in agentResponse enum
website/docs/api/spec.md Document clearContext behavior and fdc3.nothing subtype field
website/docs/api/ref/Events.md Define contextCleared event in TS and .NET
website/docs/api/ref/Channel.md Add clearContext and addEventListener to Channel interface
website/docs/api/conformance/App-Channel-Tests.md Add conformance scenarios and test IDs for context clearing
packages/fdc3-standard/src/api/Events.ts Add FDC3ContextClearedEvent TypeScript interface
packages/fdc3-standard/src/api/Channel.ts Implement clearContext and addEventListener in Channel API
packages/fdc3-schema/schemas/api/clearContextResponse.schema.json New JSON schema for clearContextResponse
packages/fdc3-schema/schemas/api/clearContextRequest.schema.json New JSON schema for clearContextRequest
packages/fdc3-schema/schemas/api/appRequest.schema.json Include clearContextRequest in appRequest schema
packages/fdc3-schema/schemas/api/agentResponse.schema.json Include clearContextResponse in agentResponse schema
packages/fdc3-agent-proxy/src/channels/DefaultChannel.ts Proxy clearContext and event listener to agent via messaging
CHANGELOG.md Note addition of clearContext API and issue resolutions
Comments suppressed due to low confidence (3)

website/docs/api/spec.md:259

  • The documentation refers to a subType field, but the actual property in events and contexts is named contextType. Update this to match the implementation.
To raise an intent without a context, use the [`fdc3.nothing`](../context/ref/Nothing) context type. This type exists so that applications can explicitly declare that they support raising an intent without a context (when registering an `IntentHandler` or in an App Directory). This type is also used when the context is cleared for the channel. If the optional context type is provided when performing [`clearContext`](ref/Channel.md#clearcontext), that type will be recorded in the field `subType` of [`fdc3.nothing`](../context/ref/Nothing) context type.

website/docs/api/ref/Events.md:248

  • In the TypeScript definition for FDC3ContextClearedEvent, the details property should use contextType instead of type to align with other language bindings and the schema.
    type: string | null;

website/docs/api/conformance/App-Channel-Tests.md:77

  • [nitpick] The test IDs ACClearContext1 and ACClearContext2 are inconsistent with the earlier ACClearHistory* naming. Consider renaming them to match the existing prefix scheme.
- `ACClearContext1`: Perform above test.

public class Fdc3ContextClearedEvent : Fdc3Event
{
public Fdc3ContextClearedEvent(string? contextType)
: base(Fdc3EventType.ContextCleared, new Fdc3ContextClearedEvent(contextType))
Copy link

Copilot AI Jul 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .NET constructor is recursively instantiating Fdc3ContextClearedEvent instead of passing a details object. It should pass a Fdc3ContextClearedEventDetails instance to the base constructor.

Suggested change
: base(Fdc3EventType.ContextCleared, new Fdc3ContextClearedEvent(contextType))
: base(Fdc3EventType.ContextCleared, new Fdc3ContextClearedEventDetails(contextType))

Copilot uses AI. Check for mistakes.
switch (type) {
case 'contextCleared':
listener = new EventListener(this.messaging, 'contextCleared', handler);
break;
Copy link

Copilot AI Jul 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The addEventListener implementation throws on null event type, but the API allows subscribing to all events with null. Consider handling null to register a listener for all event types.

Suggested change
break;
break;
case null:
listener = new EventListener(this.messaging, 'allEvents', handler); // Register for all events
break;

Copilot uses AI. Check for mistakes.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot has a point there. It looks like this is also wrong where we listener for the channelChanged event:

addEventListener(type: FDC3EventTypes | null, handler: EventHandler): Promise<Listener> {
switch (type) {
case 'userChannelChanged':
return this.channels.addChannelChangedEventHandler(handler);
default:
Logger.warn(`Tried to add a listener for an unknown event type: ${type}`);
return Promise.reject(new Error('UnknownEventType'));
}
}

Co-pilot's suggestion to fix isn't right however. Rather EventListener will probbably ned to be adjusted to be able to take multiple types:

constructor(messaging: Messaging, type: string, handler: EventHandler) {

As we need to know the specific messages it should respond to (from a set that is wider than the scope of the listener).

</Tabs>

Used to clear the specified context type if provided, otherwise, clear all context types present in the channel. The Desktop Agent MUST update its internal representation of the context in the channel and ensure that subsequent calls to [`getCurrentContext`](#getcurrentcontext) and any new joiners to that channel (through [`joinUserChannel`](DesktopAgent#joinUserChannel) or [`addContextListener`](DesktopAgent#addContextListener)) will not receive anything for either specified context type or the most recent context until new context has been broadcast to the channel.
Desktop Agents MUST also immediately notified the apps that are listening to `contextCleared` event for this channel. If a `contextType` parameter was provided, then the `contextType` field will be set to that type, otherwise, it is omitted.
Copy link

Copilot AI Jul 9, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammar: change 'immediately notified' to 'immediately notify' to correct the imperative form.

Suggested change
Desktop Agents MUST also immediately notified the apps that are listening to `contextCleared` event for this channel. If a `contextType` parameter was provided, then the `contextType` field will be set to that type, otherwise, it is omitted.
Desktop Agents MUST also immediately notify the apps that are listening to `contextCleared` event for this channel. If a `contextType` parameter was provided, then the `contextType` field will be set to that type, otherwise, it is omitted.

Copilot uses AI. Check for mistakes.
Copy link
Contributor

@kriswest kriswest left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really really ready to see this merged, as I'm sure is @kemerava!

There's one small change needed to handle the null argument on addEventListener. Up to you if applying the same fix to DesktopAgentProxy's addEventListener - if not we need to raise an issue and another PR for that.

I've also suggested that EventListener is updated to take multiple types to simplify things when we have more events - technically there is only one of each type at present so null handling is just handling that one relevant type.

switch (type) {
case 'contextCleared':
listener = new EventListener(this.messaging, 'contextCleared', handler);
break;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot has a point there. It looks like this is also wrong where we listener for the channelChanged event:

addEventListener(type: FDC3EventTypes | null, handler: EventHandler): Promise<Listener> {
switch (type) {
case 'userChannelChanged':
return this.channels.addChannelChangedEventHandler(handler);
default:
Logger.warn(`Tried to add a listener for an unknown event type: ${type}`);
return Promise.reject(new Error('UnknownEventType'));
}
}

Co-pilot's suggestion to fix isn't right however. Rather EventListener will probbably ned to be adjusted to be able to take multiple types:

constructor(messaging: Messaging, type: string, handler: EventHandler) {

As we need to know the specific messages it should respond to (from a set that is wider than the scope of the listener).

await listener.register();
return listener;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we're going to need some cucumber tests for this otherwise you'll see the coverage dip!

// first, ensure channel state is up-to-date
const request: ClearContextRequest = {
meta: this.messaging.createMeta(),
payload: {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, there will need to be support for this event added to the BroadcastHandler in the fdc3-web-impl, plus tests of the same there.

A context type may also be associated with multiple intents. For example, an `fdc3.instrument` could be associated with `ViewChart`, `ViewNews`, `ViewAnalysis` or other intents.

To raise an intent without a context, use the [`fdc3.nothing`](../context/ref/Nothing) context type. This type exists so that applications can explicitly declare that they support raising an intent without a context (when registering an `IntentHandler` or in an App Directory).
To raise an intent without a context, use the [`fdc3.nothing`](../context/ref/Nothing) context type. This type exists so that applications can explicitly declare that they support raising an intent without a context (when registering an `IntentHandler` or in an App Directory). This type is also used when the context is cleared for the channel. If the optional context type is provided when performing [`clearContext`](ref/Channel.md#clearcontext), that type will be recorded in the field `subType` of [`fdc3.nothing`](../context/ref/Nothing) context type.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unsure if this is still current. @kriswest indicated that the approach had been changed from using fdc3.nothing to the event based workflow. Is this still accurate?

@kemerava kemerava changed the base branch from main to 1197-context-clearing July 29, 2025 12:44
@kemerava
Copy link
Contributor Author

Merging to the new branch, will create another PR from that into main

@kemerava kemerava merged commit 660182d into finos:1197-context-clearing Jul 29, 2025
6 of 7 checks passed
@kemerava kemerava mentioned this pull request Jul 29, 2025
17 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Context Clearing

6 participants