Summary
Factory.#issueSource() silently guesses Linear when config.issueSource is unset and /linear/issues happens to be mounted. This is a latent routing defect: the active contract requires Factory to refuse to route when issueSource is absent, not infer a provider from mount availability.
This is not currently firing in production. The deployed factory-cloud config template explicitly sets issueSource: "github", so this probe is bypassed there. This issue is preventive: the first profile shipped without that field can hit it.
Defects
- Mount presence is treated as intent. The current code calls
ensureSubRoot(ISSUE_ROOT) and resolves linearReady === 'ready' ? 'linear' : 'github'. A mounted /linear/issues therefore silently selects Linear even when the intended issue surface is GitHub.
- The guessed result is process-lifetime sticky.
#resolvedIssueSource memoizes the first probe. A transient/startup mount outcome pins routing until the Factory process is restarted.
- Logging is backwards. Factory logs only when the guess resolves to GitHub (
Linear issue source is not connected; using GitHub issues). The more dangerous outcome—silently resolving to Linear—emits no decision log at all.
Contract contradiction
The operating manual says that when the active contract leaves issueSource unset, Factory must refuse to route rather than assume Linear, and explicitly warns that “assuming Linear is exactly the defect this replaced.” The current fallback reintroduces that behavior.
Expected behavior
- Treat an unset
issueSource as a configuration error/refusal to route.
- Do not infer routing intent from whether a provider subroot happens to mount.
- If any compatibility fallback is retained, do not memoize a transient probe indefinitely and log every resolved routing decision symmetrically.
Scope
Please fix and test this separately. It is intentionally not being changed in the silent-empty discovery observability PR.
Summary
Factory.#issueSource()silently guesses Linear whenconfig.issueSourceis unset and/linear/issueshappens to be mounted. This is a latent routing defect: the active contract requires Factory to refuse to route whenissueSourceis absent, not infer a provider from mount availability.This is not currently firing in production. The deployed
factory-cloudconfig template explicitly setsissueSource: "github", so this probe is bypassed there. This issue is preventive: the first profile shipped without that field can hit it.Defects
ensureSubRoot(ISSUE_ROOT)and resolveslinearReady === 'ready' ? 'linear' : 'github'. A mounted/linear/issuestherefore silently selects Linear even when the intended issue surface is GitHub.#resolvedIssueSourcememoizes the first probe. A transient/startup mount outcome pins routing until the Factory process is restarted.Linear issue source is not connected; using GitHub issues). The more dangerous outcome—silently resolving to Linear—emits no decision log at all.Contract contradiction
The operating manual says that when the active contract leaves
issueSourceunset, Factory must refuse to route rather than assume Linear, and explicitly warns that “assuming Linear is exactly the defect this replaced.” The current fallback reintroduces that behavior.Expected behavior
issueSourceas a configuration error/refusal to route.Scope
Please fix and test this separately. It is intentionally not being changed in the silent-empty discovery observability PR.