Repair Jira integration fixtures and verification contracts (#28743)

## ELI5

Keep the test suite working with the Jira features that have just landed. There is no visible app change.

## What Changed

The host-picker test now expects the host-qualified selection the parent already accepts. The startup fixture provides Electron's protocol handler and verifies that ready installs the Jira image scheme. Jira edit tests use exported wrappers with module-local setters that are cleared on unmount, preserving the issue/source switch tests without the banned mutable function export.

The WSL storage inventory classifies Jira list columns, linked-view choice and prompt templates as device preferences, matching their keys and the existing Linear policy. Skill-guide tests check the actual generated discovery projection rather than assuming it is shorter than every full guide or uses one fixed phrase. The cache test follows the headless workflow's deliberate removal of its push trigger; cache-warmer checks remain intact.

## Why

Final CI found six stale integration assumptions after the Jira batch. Updating the fixtures and inventory preserves the landed behavior and the underlying checks. Changing production code, padding the Jira guide, or restoring an intentionally removed workflow trigger would change the product to satisfy incorrect test assumptions.

## Linked Issue

Follow-up to #28622, #28631 and #28592. The existing headless trigger policy was introduced in #28664.

## Visual Proof

N/A — tests, test fixtures and storage inventory declarations only; no visual or interaction change.

## Testing

- [x] Automated tests updated.
- [x] 196 focused tests across nine files pass on macOS, covering every failed shard assertion, fixture consumers and the headless workflow policy.
- [x] Node and web typechecks pass; all seven changed-code quality stages, formatting and diff checks pass.
- Reproduced five failing assertions in startup/export/storage tests and the skill projection failure before the repairs. The host-picker owner also reproduced the stale selection failure before correcting it.
- Final full CI will run on this PR. The prior Ubuntu 22.04 persistence job crashed in the native watcher build before persistence tests ran; this change does not claim a Linux release, live Jira or real SSH pass.

## Review

Independent source review found no issues; all six reviewed file hashes and the complete diff match committed head `aa703eb50147ba95646cb82f10b6d86b4f890fc4`. Risk: low. No authentication, network, protocol implementation, workflow, renderer behavior, remote messages or migration rewrite logic changes.

## Agent skill upstream boundary

- [x] Not applicable; no upstream skill-installer source or artifacts copied.

## Notes

The three storage keys contain device-level preferences, without workspace paths or identifiers. Tests preserve host disambiguation and issue/source switching. Platform, SSH and provider behavior remains in the existing implementations.

## Checklist

- [x] Small and focused.
- [x] Explained the before/after, mechanism and choice of approach.
- [x] Visual proof marked N/A with a reason.
- [x] Self-reviewed for correctness and cleanup.
- [x] Cross-platform and SSH impact considered.
- [x] Focused tests, types, formatting and quality checks pass; full CI covers the broader build.
This commit is contained in:
Neil
2026-10-14 06:37:44 -07:00
committed by GitHub
parent c8ed629217
commit dd4d0fa51f
6 changed files with 42 additions and 11 deletions
@@ -11,6 +11,7 @@ import {
STUB_TOPICS,
assertAliasContract,
buildArtifacts,
composeStubProjection,
frontmatterBlock,
normalizeMarkdown,
parseFrontmatter,
@@ -72,16 +73,19 @@ afterEach(async () => {
describe('bundled skill guide generator', () => {
it('projects stub topics as hybrid discovery stubs that reuse the guide frontmatter', async () => {
expect(STUB_TOPICS.length).toBeGreaterThan(0)
const sharedBlocks = await readSharedStubBlocks(projectDir)
for (const name of STUB_TOPICS) {
const source = await readFile(path.join(projectDir, 'skill-guides', `${name}.md`), 'utf8')
const projection = await readFile(path.join(projectDir, 'skills', name, 'SKILL.md'), 'utf8')
const stubBody = await readFile(path.join(projectDir, 'skill-stubs', `${name}.md`), 'utf8')
// The routing frontmatter is the unchanged discovery surface.
expect(projection.startsWith(frontmatterBlock(source, `${name}.md`))).toBe(true)
// The stub is a thin hybrid pointer, not the full guide.
// Shared CLI resolution can be longer than a short topic's full guide.
expect(projection).not.toEqual(source)
expect(projection.length).toBeLessThan(source.length)
expect(projection).toContain('discovery stub')
expect(projection).toEqual(
composeStubProjection(source, stubBody, `skill-stubs/${name}.md`, { sharedBlocks })
)
expect(projection).toContain(`skills get ${name}`)
}
})
@@ -195,9 +195,7 @@ it('uses exact optional restores, seeds only main and retains full dependency fa
).toBe(
"steps.scope.outputs.graph_required == 'true' && steps.compiler.outputs.available != 'true'"
)
for (const event of ['push', 'pull_request']) {
expect(workflow.on[event].paths).toContain('.github/actions/prepare-headless-compiler/**')
}
expect(workflow.on.pull_request.paths).toContain('.github/actions/prepare-headless-compiler/**')
const warmer = parse(readFileSync('.github/workflows/ci-cache-warmup.yml', 'utf8'))
const warmSteps = warmer.jobs.warm.steps
expect(
@@ -3,6 +3,7 @@ import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'
import type * as DurableFileWrite from '../durable-file-write'
import { JIRA_IMAGE_SCHEME } from '../../shared/jira-attachment-image'
const ORCA_PROFILE_ID = 'local-default'
const RETIRED_PROFILE_ID = '11111111-1111-4111-8111-111111111111'
@@ -22,6 +23,7 @@ const mocks = vi.hoisted(() => ({
store: null
},
openMainWindow: vi.fn(),
handleProtocol: vi.fn(),
runtimeRpcStart: vi.fn(async () => {}),
// The identity record's only writer. Watching this is what makes the pin real: asserting on
// writeFileAtomically watched a function the identity store never calls.
@@ -42,6 +44,7 @@ vi.mock('../durable-file-write', async (importOriginal) => {
})
vi.mock('electron', () => ({
protocol: { handle: mocks.handleProtocol },
app: {
on: vi.fn(),
setName: vi.fn(),
@@ -283,6 +286,10 @@ async function runReady(): Promise<void> {
openMainWindow: mocks.openMainWindow,
handleMacAppActivation: vi.fn()
})
expect(mocks.handleProtocol).toHaveBeenCalledExactlyOnceWith(
JIRA_IMAGE_SCHEME,
expect.any(Function)
)
}
function identityRecordWrites(): unknown[] {
@@ -300,6 +307,7 @@ describe('ready-phase browser identity authority', () => {
beforeEach(() => {
vi.resetModules()
mocks.openMainWindow.mockClear()
mocks.handleProtocol.mockClear()
mocks.runtimeRpcStart.mockClear()
mocks.writeFileDurableSync.mockClear()
mocks.state.isServeMode = false
@@ -899,7 +899,7 @@ describe('NewWorkspaceComposerCard folder task source mode', () => {
expect(builderItem).toBeTruthy()
act(() => builderItem?.click())
expect(hostChanges).toEqual(['setup-builder'])
expect(hostChanges).toEqual(['["setup-builder","ssh:builder"]'])
expect(recipeChanges).toEqual([null])
})
})
@@ -98,8 +98,22 @@ export function jiraIssue(title: string, overrides: Partial<JiraIssue> = {}): Ji
export const otherIssue = jiraIssue('Other issue', { id: '10002', key: 'ENG-2' })
export let selectIssue = (_issue: JiraIssue | null): void => undefined
export let selectSource = (_source: TaskSourceContext): void => undefined
let selectIssueImplementation: ((issue: JiraIssue | null) => void) | null = null
let selectSourceImplementation: ((source: TaskSourceContext) => void) | null = null
export function selectIssue(issue: JiraIssue | null): void {
if (!selectIssueImplementation) {
throw new Error('Render StoreBackedWorkspace before selecting an issue')
}
selectIssueImplementation(issue)
}
export function selectSource(source: TaskSourceContext): void {
if (!selectSourceImplementation) {
throw new Error('Render StoreBackedWorkspace before selecting a source')
}
selectSourceImplementation(source)
}
export const initialSource: TaskSourceContext = {
kind: 'task-source',
provider: 'jira',
@@ -124,8 +138,12 @@ export function StoreBackedWorkspace({ initial }: { initial: JiraIssue }): React
)
)
useLayoutEffect(() => {
selectIssue = setIssue
selectSource = setSource
selectIssueImplementation = setIssue
selectSourceImplementation = setSource
return () => {
selectIssueImplementation = null
selectSourceImplementation = null
}
}, [])
return (
<TooltipProvider>
@@ -53,6 +53,9 @@ export const LOCAL_STORAGE_MODULE_DISPOSITIONS: Record<string, WslMoveFieldDispo
'src/renderer/src/components/github-project/column-widths.ts',
'src/renderer/src/components/github-project/columns.ts',
'src/renderer/src/components/github-project/roadmap-zoom-preference.ts',
'src/renderer/src/components/jira-linked-view-storage.ts',
'src/renderer/src/components/jira-list-columns.ts',
'src/renderer/src/components/jira-prompt-templates.ts',
'src/renderer/src/components/landing-preflight-dismissal.ts',
'src/renderer/src/components/linear-issue-view-storage.ts',
'src/renderer/src/components/native-chat/NativeChatStructuredSession.test-harness.tsx',