Skip to content

Commit 874dc3d

Browse files
TheLarkInnCopilot
andcommitted
Address reporter contract review feedback
Assistant-model: GitHub Copilot Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 90cfc9a4-cbde-48e6-a771-86ad7abf948c
1 parent 67bcef3 commit 874dc3d

7 files changed

Lines changed: 50 additions & 17 deletions

File tree

common/reviews/api/reporter.api.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export interface IReporterContext {
6363
}
6464

6565
// @beta
66-
export type IReporterEmitEventInput<TPayload> = Omit<IReporterEventEnvelope<TPayload>, 'eventId' | 'sequence' | 'timestamp'>;
66+
export type IReporterEmitEventInput<TPayload> = Omit<IReporterEventEnvelope<TPayload>, 'eventId' | 'sequence' | 'sourceSequence' | 'timestamp'>;
6767

6868
// @beta
6969
export interface IReporterEventEnvelope<TPayload = unknown> {
@@ -118,19 +118,19 @@ export interface IReporterHandshakeResult {
118118

119119
// @beta
120120
export interface IReporterHello {
121-
readonly capabilities: string[];
121+
readonly capabilities: readonly string[];
122122
readonly kind: 'hello';
123123
readonly producerVersion: string;
124124
readonly protocolVersion: IReporterProtocolVersion;
125-
readonly requiredFeatures: string[];
125+
readonly requiredFeatures: readonly string[];
126126
}
127127

128128
// @beta
129129
export interface IReporterHelloAck {
130-
readonly acceptedCapabilities: string[];
130+
readonly acceptedCapabilities: readonly string[];
131131
readonly kind: 'helloAck';
132132
readonly protocolVersion: IReporterProtocolVersion;
133-
readonly rejectedRequiredFeatures: string[];
133+
readonly rejectedRequiredFeatures: readonly string[];
134134
}
135135

136136
// @beta

libraries/reporter/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,8 @@ This package is released as a public beta. Exported contracts may change before
66

77
## Links
88

9-
- [CHANGELOG.md](
10-
https://github.com/microsoft/rushstack/blob/main/libraries/reporter/CHANGELOG.md) - Find
11-
out what's new in the latest version
9+
- [CHANGELOG.md](https://github.com/microsoft/rushstack/blob/main/libraries/reporter/CHANGELOG.md) - Find out
10+
what's new in the latest version
1211
- [API Reference](https://api.rushstack.io/pages/reporter/)
1312

1413
`@rushstack/reporter` is part of the [Rush Stack](https://rushstack.io/) family of projects.

libraries/reporter/src/manager/ReporterManager.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ export class ReporterManager implements IReporterEventSink {
179179
* `timestamp`, and returns the assigned `eventId`.
180180
*/
181181
public emit<TPayload>(event: IReporterEmitEventInput<TPayload>): string {
182+
this._ensureInitialized();
182183
const eventId: string = `evt_${this._nextEventId++}`;
183184
const envelope: IReporterEventEnvelope<TPayload> = {
184185
...event,
@@ -200,6 +201,7 @@ export class ReporterManager implements IReporterEventSink {
200201
* @returns the ingested event's `eventId`
201202
*/
202203
public ingestForeignEnvelope(envelope: IReporterEventEnvelope<unknown>): string {
204+
this._ensureInitialized();
203205
const rehomed: IReporterEventEnvelope<unknown> = {
204206
...envelope,
205207
sequence: this._nextSequence++,
@@ -273,6 +275,12 @@ export class ReporterManager implements IReporterEventSink {
273275
}
274276
}
275277

278+
private _ensureInitialized(): void {
279+
if (!this._initialized) {
280+
throw new Error('ReporterManager must be initialized before publishing events.');
281+
}
282+
}
283+
276284
private _enqueue(entry: IReporterEntry, envelope: IReporterEventEnvelope<unknown>): void {
277285
const lastIndex: number = entry.queue.length - 1;
278286
if (

libraries/reporter/src/producers/IReporterEventSink.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import type { IReporterEventEnvelope } from '../events/IReporterEventEnvelope';
77
* The fields of an event envelope that a producer supplies when emitting.
88
*
99
* @remarks
10-
* The sink assigns `eventId`, the authoritative `sequence`, and the `timestamp`,
11-
* so producers never provide them.
10+
* The sink assigns `eventId`, the authoritative `sequence`, `sourceSequence`,
11+
* and the `timestamp`, so producers never provide them.
1212
*
1313
* @beta
1414
*/
1515
export type IReporterEmitEventInput<TPayload> = Omit<
1616
IReporterEventEnvelope<TPayload>,
17-
'eventId' | 'sequence' | 'timestamp'
17+
'eventId' | 'sequence' | 'sourceSequence' | 'timestamp'
1818
>;
1919

2020
/**
@@ -32,7 +32,7 @@ export interface IReporterEventSink {
3232
* Publishes an event and returns its assigned event id.
3333
*
3434
* @param event - the event envelope without the sink-assigned `eventId`,
35-
* `sequence`, and `timestamp`
35+
* `sequence`, `sourceSequence`, and `timestamp`
3636
* @returns the `eventId` assigned to the published event
3737
*/
3838
emit<TPayload>(event: IReporterEmitEventInput<TPayload>): string;

libraries/reporter/src/producers/IScopedReporter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export interface IScopedReporter {
5858
emitMessage(options: IScopedMessageOptions): string;
5959

6060
/**
61-
* Emits a structured diagnostic and returns its assigned diagnostic id.
61+
* Emits a structured diagnostic and returns its assigned event id.
6262
*/
6363
emitDiagnostic(diagnostic: IRushDiagnostic): string;
6464

libraries/reporter/src/protocol/ReporterHandshake.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ export interface IReporterHello {
3030
/**
3131
* Optional capabilities the producer can use if the consumer supports them.
3232
*/
33-
readonly capabilities: string[];
33+
readonly capabilities: readonly string[];
3434

3535
/**
3636
* Correctness-critical features the producer requires the consumer to support.
3737
*/
38-
readonly requiredFeatures: string[];
38+
readonly requiredFeatures: readonly string[];
3939
}
4040

4141
/**
@@ -57,12 +57,12 @@ export interface IReporterHelloAck {
5757
/**
5858
* The subset of the producer's capabilities the consumer accepted.
5959
*/
60-
readonly acceptedCapabilities: string[];
60+
readonly acceptedCapabilities: readonly string[];
6161

6262
/**
6363
* The producer's required features the consumer does not support.
6464
*/
65-
readonly rejectedRequiredFeatures: string[];
65+
readonly rejectedRequiredFeatures: readonly string[];
6666
}
6767

6868
/**

libraries/reporter/src/test/Manager.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,32 @@ function makeInput(
6464
}
6565

6666
describe('ReporterManager ordering and assignment', () => {
67+
it('rejects in-process events before reporters are initialized', () => {
68+
const manager: ReporterManager = new ReporterManager();
69+
manager.addReporter(new RecordingReporter('a'));
70+
71+
expect(() => manager.emit(makeInput('commandStarted'))).toThrow(/must be initialized/);
72+
});
73+
74+
it('rejects foreign envelopes before reporters are initialized', () => {
75+
const manager: ReporterManager = new ReporterManager();
76+
manager.addReporter(new RecordingReporter('a'));
77+
const foreign: IReporterEventEnvelope<unknown> = {
78+
protocolVersion: { major: 1, minor: 0 },
79+
eventId: 'child_evt',
80+
sessionId: 'child',
81+
sequence: 42,
82+
timestamp: '2026-01-01T00:00:01.000Z',
83+
source: { packageName: '@rushstack/heft', packageVersion: '1.2.19' },
84+
privacy: 'public',
85+
required: false,
86+
type: 'externalOutput',
87+
payload: {}
88+
};
89+
90+
expect(() => manager.ingestForeignEnvelope(foreign)).toThrow(/must be initialized/);
91+
});
92+
6793
it('assigns monotonic sequence, event ids, and timestamps in order', async () => {
6894
const manager: ReporterManager = new ReporterManager({ now: () => '2026-01-01T00:00:00.000Z' });
6995
const reporter: RecordingReporter = new RecordingReporter('a');

0 commit comments

Comments
 (0)