-
Notifications
You must be signed in to change notification settings - Fork 340
[comp] Production Deploy #3293
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
[comp] Production Deploy #3293
Changes from all commits
Commits
Show all changes
36 commits
Select commit
Hold shift + click to select a range
4f4c6f5
feat(api): add inference.net Catalyst tracing for LLM observability
Marfuen 5449f91
Merge branch 'main' into mariano/inference-tracing-integration
Marfuen 7f7eb49
feat(integration-platform): version + rollback for dynamic check edits
tofikwest 487a4d9
feat(integration-platform): failure classifier for the self-heal layer
tofikwest aa1bba8
feat(integration-platform): inconclusive run status + failure partition
tofikwest b191fcc
feat(integration-platform): hold our-side dynamic failures (scheduled…
tofikwest b374c89
feat(integration-platform): hold our-side dynamic failures (manual ru…
tofikwest 59c879e
feat(integration-platform): mark held dynamic check-runs as inconclusive
tofikwest 32e0295
feat(integration-platform): inconclusive-runs queue endpoint for the …
tofikwest 3d58ddb
chore: merge release v3.92.4 back to main [skip ci]
github-actions[bot] 713fe32
perf(db): use composite (checkId, createdAt) index for check version …
tofikwest a56a826
Merge branch 'main' into tofik/dynamic-check-versioning
tofikwest 8fdf5e1
fix(self-heal): only surface checks whose latest run is still inconcl…
tofikwest a24b9af
fix(self-heal): hide held (inconclusive) runs from the customer task UI
tofikwest 333f753
fix(self-heal): mark manual held dynamic runs inconclusive (consisten…
tofikwest 63fb53a
feat(self-heal): persisting re-run endpoint so fixed checks flip cust…
tofikwest 98201f1
fix(self-heal): redact quoted JSON keys/values + short secrets (cubic…
tofikwest 83915c2
fix(policies): preserve acceptances when republishing unchanged polic…
tofikwest 425ecb6
fix(self-heal): cubic — broaden HTTP status parse + held failures blo…
tofikwest ae4cc47
fix(self-heal): redact quoted secret values containing spaces (cubic P1)
tofikwest 95b6f88
fix(self-heal): held runs store failedCount 0 + document done-on-held…
tofikwest 59f8a63
fix(self-heal): cubic backlog — empty-msg mask, string status, bounde…
tofikwest da2e923
fix(self-heal): anchor status-string parse + reuse decideRunStatus in…
tofikwest 961f931
Merge pull request #3287 from trycompai/tofik/dynamic-check-versioning
tofikwest d1c4b2b
Merge branch 'main' into tofik/cs-587-bug-policy-stuck-in-needs
tofikwest 9b098de
Merge pull request #3292 from trycompai/tofik/cs-587-bug-policy-stuck…
tofikwest b7adfb6
chore(auth): disable unused email/password login
tofikwest 1981bc3
Merge branch 'main' into tofik/disable-email-password-auth
tofikwest 1838068
chore: merge release v3.92.5 back to main [skip ci]
github-actions[bot] fd0fed6
Merge branch 'main' into tofik/disable-email-password-auth
tofikwest 32b95c3
Merge pull request #3294 from trycompai/tofik/disable-email-password-…
tofikwest 37061b7
Merge remote-tracking branch 'origin/main' into tofik/inference-traci…
tofikwest a14bd87
feat(self-heal): include the evidence-task title in the agent queue
tofikwest c868c3e
Merge pull request #2939 from trycompai/mariano/inference-tracing-int…
tofikwest eba88c5
Merge branch 'main' into tofik/dynamic-check-versioning
tofikwest 496db80
Merge pull request #3297 from trycompai/tofik/dynamic-check-versioning
tofikwest File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| import * as ai from 'ai'; | ||
| import { setup, type CatalystTracing } from '@inference/tracing'; | ||
| import { createAISdkTelemetrySettings } from '@inference/tracing/ai-sdk'; | ||
|
|
||
| let tracing: CatalystTracing | null = null; | ||
|
|
||
| export async function initTracing(): Promise<void> { | ||
| if (!process.env.CATALYST_OTLP_TOKEN) return; | ||
|
|
||
| tracing = await setup({ | ||
| serviceName: 'compai-api', | ||
| modules: { aiSdk: ai }, | ||
| }); | ||
|
|
||
| console.log( | ||
| `Catalyst tracing enabled → ${tracing.endpoint} as ${tracing.serviceName}`, | ||
| ); | ||
| } | ||
|
|
||
| export async function shutdownTracing(): Promise<void> { | ||
| if (!tracing) return; | ||
| await tracing.shutdown(); | ||
| } | ||
|
|
||
| export function getAITelemetry(functionId: string) { | ||
| if (!tracing) return undefined; | ||
| return createAISdkTelemetrySettings(tracing.tracer, { functionId }); | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
164 changes: 164 additions & 0 deletions
164
apps/api/src/integration-platform/controllers/dynamic-integrations.versioning.spec.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,164 @@ | ||
| import { Test, TestingModule } from '@nestjs/testing'; | ||
| import { HttpException } from '@nestjs/common'; | ||
| import { DynamicIntegrationsController } from './dynamic-integrations.controller'; | ||
| import { InternalTokenGuard } from '../../auth/internal-token.guard'; | ||
| import { DynamicIntegrationRepository } from '../repositories/dynamic-integration.repository'; | ||
| import { DynamicCheckRepository } from '../repositories/dynamic-check.repository'; | ||
| import { ProviderRepository } from '../repositories/provider.repository'; | ||
| import { CheckRunRepository } from '../repositories/check-run.repository'; | ||
| import { DynamicManifestLoaderService } from '../services/dynamic-manifest-loader.service'; | ||
|
|
||
| jest.mock('@db', () => ({ db: {} })); | ||
| jest.mock('@trycompai/integration-platform', () => ({ | ||
| validateIntegrationDefinition: jest.fn(), | ||
| SyncDefinitionSchema: { parse: jest.fn() }, | ||
| })); | ||
|
|
||
| describe('DynamicIntegrationsController — check versioning', () => { | ||
| let controller: DynamicIntegrationsController; | ||
|
|
||
| const INTEGRATION_ID = 'din_abc'; | ||
| const CHECK_ID = 'dck_abc'; | ||
|
|
||
| const oldCheck = { | ||
| id: CHECK_ID, | ||
| integrationId: INTEGRATION_ID, | ||
| definition: { steps: [{ type: 'code', code: 'OLD' }] }, | ||
| variables: [{ key: 'region' }], | ||
| }; | ||
|
|
||
| const dynamicCheckRepo = { | ||
| findById: jest.fn(), | ||
| update: jest.fn(), | ||
| recordVersion: jest.fn(), | ||
| listVersions: jest.fn(), | ||
| findVersionById: jest.fn(), | ||
| }; | ||
| const loaderService = { invalidateCache: jest.fn() }; | ||
|
|
||
| beforeEach(async () => { | ||
| jest.clearAllMocks(); | ||
| dynamicCheckRepo.findById.mockResolvedValue(oldCheck); | ||
| dynamicCheckRepo.update.mockResolvedValue(oldCheck); | ||
| dynamicCheckRepo.recordVersion.mockResolvedValue({ id: 'dckv_1' }); | ||
| loaderService.invalidateCache.mockResolvedValue(undefined); | ||
|
|
||
| const module: TestingModule = await Test.createTestingModule({ | ||
| controllers: [DynamicIntegrationsController], | ||
| providers: [ | ||
| { provide: DynamicIntegrationRepository, useValue: {} }, | ||
| { provide: DynamicCheckRepository, useValue: dynamicCheckRepo }, | ||
| { provide: ProviderRepository, useValue: {} }, | ||
| { provide: CheckRunRepository, useValue: {} }, | ||
| { provide: DynamicManifestLoaderService, useValue: loaderService }, | ||
| ], | ||
| }) | ||
| .overrideGuard(InternalTokenGuard) | ||
| .useValue({ canActivate: () => true }) | ||
| .compile(); | ||
|
|
||
| controller = module.get(DynamicIntegrationsController); | ||
| }); | ||
|
|
||
| describe('updateCheck', () => { | ||
| it('snapshots the OLD logic before applying the update', async () => { | ||
| await controller.updateCheck(INTEGRATION_ID, CHECK_ID, { | ||
| definition: { steps: [{ type: 'code', code: 'NEW' }] }, | ||
| source: 'agent', | ||
| note: 'fix project-scoped keys', | ||
| }); | ||
|
|
||
| // version captured the pre-change definition/variables | ||
| expect(dynamicCheckRepo.recordVersion).toHaveBeenCalledWith({ | ||
| checkId: CHECK_ID, | ||
| definition: oldCheck.definition, | ||
| variables: oldCheck.variables, | ||
| source: 'agent', | ||
| note: 'fix project-scoped keys', | ||
| }); | ||
| // version recorded BEFORE the update | ||
| const verOrder = | ||
| dynamicCheckRepo.recordVersion.mock.invocationCallOrder[0]; | ||
| const updOrder = dynamicCheckRepo.update.mock.invocationCallOrder[0]; | ||
| expect(verOrder).toBeLessThan(updOrder); | ||
| }); | ||
|
|
||
| it('strips source/note from the data forwarded to the check update', async () => { | ||
| await controller.updateCheck(INTEGRATION_ID, CHECK_ID, { | ||
| definition: { steps: [] }, | ||
| source: 'agent', | ||
| note: 'x', | ||
| }); | ||
| expect(dynamicCheckRepo.update).toHaveBeenCalledWith(CHECK_ID, { | ||
| definition: { steps: [] }, | ||
| }); | ||
| }); | ||
|
|
||
| it('still applies the update if versioning fails (best-effort)', async () => { | ||
| dynamicCheckRepo.recordVersion.mockRejectedValueOnce(new Error('boom')); | ||
| const res = await controller.updateCheck(INTEGRATION_ID, CHECK_ID, { | ||
| definition: { steps: [] }, | ||
| }); | ||
| expect(res).toEqual({ success: true }); | ||
| expect(dynamicCheckRepo.update).toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it('404s when the check does not belong to the integration', async () => { | ||
| dynamicCheckRepo.findById.mockResolvedValueOnce({ | ||
| ...oldCheck, | ||
| integrationId: 'din_other', | ||
| }); | ||
| await expect( | ||
| controller.updateCheck(INTEGRATION_ID, CHECK_ID, {}), | ||
| ).rejects.toBeInstanceOf(HttpException); | ||
| expect(dynamicCheckRepo.update).not.toHaveBeenCalled(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('restoreCheckVersion', () => { | ||
| const version = { | ||
| id: 'dckv_1', | ||
| checkId: CHECK_ID, | ||
| definition: { steps: [{ type: 'code', code: 'RESTORED' }] }, | ||
| variables: [], | ||
| }; | ||
|
|
||
| it('snapshots current state, then restores the version logic', async () => { | ||
| dynamicCheckRepo.findVersionById.mockResolvedValue(version); | ||
|
|
||
| const res = await controller.restoreCheckVersion( | ||
| INTEGRATION_ID, | ||
| CHECK_ID, | ||
| 'dckv_1', | ||
| ); | ||
|
|
||
| expect(dynamicCheckRepo.recordVersion).toHaveBeenCalledWith( | ||
| expect.objectContaining({ checkId: CHECK_ID, source: 'restore' }), | ||
| ); | ||
| expect(dynamicCheckRepo.update).toHaveBeenCalledWith(CHECK_ID, { | ||
| definition: version.definition, | ||
| variables: version.variables, | ||
| }); | ||
| expect(res).toEqual({ success: true, restoredFrom: 'dckv_1' }); | ||
| }); | ||
|
|
||
| it('404s when the version belongs to a different check', async () => { | ||
| dynamicCheckRepo.findVersionById.mockResolvedValue({ | ||
| ...version, | ||
| checkId: 'dck_other', | ||
| }); | ||
| await expect( | ||
| controller.restoreCheckVersion(INTEGRATION_ID, CHECK_ID, 'dckv_1'), | ||
| ).rejects.toBeInstanceOf(HttpException); | ||
| expect(dynamicCheckRepo.update).not.toHaveBeenCalled(); | ||
| }); | ||
| }); | ||
|
|
||
| describe('listCheckVersions', () => { | ||
| it('returns the version history for the check', async () => { | ||
| dynamicCheckRepo.listVersions.mockResolvedValue([{ id: 'dckv_1' }]); | ||
| const res = await controller.listCheckVersions(INTEGRATION_ID, CHECK_ID); | ||
| expect(res).toEqual({ versions: [{ id: 'dckv_1' }] }); | ||
| }); | ||
| }); | ||
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
P1: New check-version endpoints are added without RBAC enforcement, so access is gated only by internal token instead of permission-scoped API authorization.
Prompt for AI agents