The **same** defect as the GitLab importer fixed in #2843, in a plugin written from the same template — found only because I re-grepped my own area with a wider pattern after declaring it clean. ```ts export function buildLinearTaskCreateInput(issue: LinearIssue): TaskCreateInput { return { title, description, column: "triage", … }; } ``` `triage` was **deleted by U11**; the default board's lanes are `todo | in-progress | in-review | done | archived`. An explicit `column` **overrides** the intake column `createTask` resolves for the workflow it selects — which is precisely how the literal survived the deletion. Nothing rejects the write and nothing logs it: the route answers with a task id, and the card is not on the board. Fix: omit `column`, exactly as #2843 did for GitLab. ## Two tests were pinning the bug ```ts expect(input.column).toBe("triage"); // import-linear.test.ts expect(createTask).toHaveBeenCalledWith(objectContaining({ column: "triage" })); // routes.test.ts ``` That is how this survived a lifecycle sweep that *did* reach the GitLab importer. The census cannot see a lane literal passed as a **call argument**, and the tests asserted the behaviour was intended — so both the automated check and the human check said this file was fine. Both now assert the column is **absent**, which is the property that hands the decision to `createTask` and the one that fails on revert. ## The finding worth carrying forward "We fixed the import path" was true of the forge everybody uses and false of the other one. Two importers, one template, one of them audited. When a defect is found in a file that had a sibling, the sibling is the next place to look — and it is not something the census will tell you, because this whole class is invisible to it. ## Revert proof (measured) Restore `column: "triage"`: ``` AssertionError: expected 'triage' to be undefined AssertionError: expected "vi.fn()" to be called with arguments: [ ObjectNotContaining{…} ] ``` ## Verification - `pnpm test:gate` — 161 / 487 / 13 / 71 passed - `pnpm lint` — clean - `tsc --noEmit` (`@fusion-plugin-examples/linear-import`) — clean - full plugin suite — 35 passed across 5 files - census `--strict` — exit 0 (unchanged: this class is invisible to it) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Linear Import Plugin
fusion-plugin-linear-import is a bundled Fusion integration plugin that imports Linear issues into Fusion tasks. It is intentionally implemented through plugin settings, plugin routes, plugin tools, and a plugin dashboard view — not through core Linear settings or host-owned /api/linear/* routes.
Setup
- Install or enable Linear Import from Settings → Plugins / Plugin Manager.
- Open the plugin settings and enter a Linear personal API key.
- Optionally set a default team key/ID, issue state filter, and assignee ID.
- Open the Linear Import plugin dashboard view to browse and import issues.
The API key is a plugin password setting. Fusion uses it only for HTTPS GraphQL requests to Linear and does not include it in route responses, tool results, task descriptions, task documents, or logs.
Supported filters
The dashboard view, routes, and tools share the same filters:
query— matches issue title, description, or identifier.teamKey/teamId— Linear team key or UUID.state—active,backlog,started,unstarted,completed,canceled, orall.assigneeId— Linear user UUID.limit— bounded to 1–100 issues.after— optional Linear pagination cursor for browse calls.
Routes
All routes are plugin-scoped under /api/plugins/fusion-plugin-linear-import/*:
GET /status— checks whether the plugin has a usable API key.POST /issues— lists/searches issues.POST /issues/detail— fetches one issue by UUID or identifier.POST /issues/import— imports one issue intotriage.POST /issues/import-batch— imports up to 25 selected issues.
Dashboard requests include projectId when the host provides one so the plugin uses the project-scoped plugin settings and task store.
Agent tools
The plugin registers plugin tools (not built-in fn_* tools):
linear_import_browse_issueslinear_import_issuelinear_import_issues
Tool results summarize imported/skipped issues and include safe issue/task details only.
Import behavior and duplicate handling
Imported tasks are created in triage. The task description contains the Linear issue body or (no description), followed by Source: <Linear URL>, the Linear identifier, team, and state. Task provenance stores:
sourceIssue.provider: "linear"- stable Linear issue id as
sourceIssue.externalIssueId - source URL
source.sourceType: "api"source.sourceMetadata.provider: "linear"- Linear issue id, identifier, URL, team, state, assignee, and timestamps where available
Duplicate detection checks non-archived tasks by Linear issue id, Linear identifier, and source URL before creating a task. Duplicate route/tool responses identify the existing Fusion task id when available.
Limitations and non-goals
- No Linear CLI or binary dependency is required or installed.
- No host-owned
/api/linear/*routes or core Linear settings are added. - Imports are read-only with respect to Linear; the plugin does not comment on, close, reopen, or update Linear issues.
- Linear workspace/team permissions are determined by the configured API key.
External Integration Evidence
- Canonical upstream repo URL:
upstream-pending-verification(Linear is consumed as a SaaS HTTP/GraphQL API; no official client repository is required) - Docs / homepage URL: https://developers.linear.app/
- API docs URL: https://developers.linear.app/docs/graphql/working-with-the-graphql-api
- GraphQL API endpoint: https://api.linear.app/graphql
- Release / download URL:
upstream-pending-verification(no downloadable binary is added) - Binary / CLI name:
none(HTTP/GraphQL API integration only) - Checksum:
upstream-pending-verification(no downloaded binary is added)