CI contract validation
Fail pull requests when a Shardwire app manifest, intents, subscriptions, or expectedScope drift from what production should negotiate.
Shardwire already gives you everything needed to treat the bridge as a versioned contract:
defineShardwireAppfor required events, actions, and filter keysdiagnoseShardwireAppfor structured issuesgenerateSecretScopefor minimum secret shape- optional
expectedScopefor maximum allowed negotiation
CI should exercise the same checks so bad merges cannot ship.
Recommended approach
-
Export the manifest (and optional
expectedScopeobject) from a small module your app and tests import. -
In CI, build a frozen negotiation fixture: the
BridgeCapabilitiesobject your bot is supposed to expose for that secret in production (events/actions arrays). Check this file in when you intentionally change capabilities. -
Run
diagnoseShardwireApp(manifest, negotiatedFixture, options)with:botIntentsmatchingcreateBotBridge({ intents })subscriptionslisting every{ name, filter? }your app registers before strictreadyexpectedScopewhen you use it inapp.ready
-
Fail the job when
!report.okand printformatShardwireDiagnosis(report)so logs are readable.
Example (Vitest-style)
import { describe, expect, it } from 'vitest';
import { diagnoseShardwireApp, formatShardwireDiagnosis } from 'shardwire';
import { appManifest } from '../src/shardwire-manifest.js';
import { productionNegotiatedCapabilities } from '../fixtures/shardwire-negotiated.js';
describe('Shardwire contract', () => {
it('matches production negotiation and intents', () => {
const report = diagnoseShardwireApp(appManifest, productionNegotiatedCapabilities, {
strictIntentCheck: true,
botIntents: ['Guilds', 'GuildMessages', 'MessageContent'],
subscriptions: [{ name: 'messageCreate', filter: { guildId: '123' } }],
});
if (!report.ok) {
console.error(formatShardwireDiagnosis(report, { title: 'Shardwire CI' }));
}
expect(report.ok).toBe(true);
});
});Keep productionNegotiatedCapabilities updated whenever you change bot intents, secret allow lists, or which apps connect.
What this catches early
- required events or actions missing from negotiation
- manifest events whose intents are not enabled on the bot
- runtime subscriptions or filter keys not declared on the manifest
expectedScopeviolations when negotiation is broader than intended
Related
- Strict startup for the runtime gate
- Incremental adoption for staged rollout