fancive_obsidian-parallel-r.../.e2e
wujunchen 5f36b1218b feat: provider/lifecycle robustness, onboarding nudge, CI coverage gate
Assessment-driven batch of 10 verified, low-risk improvements. All gates green
(typecheck, biome, obsidian lint + strict review, 28 test files, branch
coverage 100%, e2e gate).

Correctness:
- provider-request: decide structured-output fallback on HTTP status via a new
  ProviderApiError (status+body) instead of pattern-matching the i18n-translated
  message — previously only en/zh matched, so fr/de/es/ja/ko users hit silent
  permanent failures when a provider rejected json_schema.
- streaming: surface in-stream provider error payloads ({type:'error'} /
  {error:{}}) by throwing, instead of swallowing them and later misreporting a
  transient overload/quota error as "non-JSON LLM output". Note: detection runs
  outside the JSON.parse try/catch so the throw is not swallowed.
- main: throwIfCancelled before cacheManager.put so a cancelled job cannot
  poison the cache.
- generation-job-manager: add cancelAll(); onunload now cancels in-flight jobs
  (aborting streaming HTTP + SIGKILL-ing CLI children), not just queued waiters.

Onboarding / UX:
- settings: DEFAULT_SETTINGS.promptLanguage 'zh' -> 'auto' so new non-Chinese
  users get source-language summaries by default (existing users unaffected).
- view/main/types: first-run "Set up AI provider" CTA in the empty state when no
  credential is configured (PluginHost.openSettings + isCredentialConfigured).
- error-ui/generation-job-manager/types: new 'network' ErrorKind with an
  actionable notice + Retry for offline/connection failures.
- i18n-strings: 4 new keys across all 7 locales (parity test enforced).

CI / docs:
- .c8rc.json + package.json: branch-coverage gate (check-coverage, branches=100,
  degenerate metrics disabled) and preserve c8's exit code in the coverage script.
- ci.yml: run coverage gate and strict obsidian review in CI.
- README: fix Obsidian version badge 1.4.0 -> 1.8.7 (matches manifest).
- e2e product-shell DOM shim: add createSpan (was missing; real Obsidian has it).

Tests: cover the status-based fallback (incl. non-English locale), in-stream
error throwing, cancelAll, and network classification.

Change-Id: Ic619098aa7cdf3dc1c444be4bb8a445550eadf55
2026-06-16 09:37:59 +08:00
..
cases feat: provider/lifecycle robustness, onboarding nudge, CI coverage gate 2026-06-16 09:37:59 +08:00
scripts ci(e2e): enforce self-contained release gate 2026-04-30 14:45:56 +08:00
config.yaml ci(e2e): enforce self-contained release gate 2026-04-30 14:45:56 +08:00
gate.sh ci(e2e): enforce self-contained release gate 2026-04-30 14:45:56 +08:00
hook.sh chore: add e2e contract gate 2026-04-29 14:08:38 +08:00
README.md ci(e2e): enforce self-contained release gate 2026-04-30 14:45:56 +08:00
run.sh ci(e2e): enforce self-contained release gate 2026-04-30 14:45:56 +08:00

E2E Contract

This repository uses .e2e/run.sh as the project-local runtime entry point. The runner clears stale artifacts, executes the release-grade test pipeline (build → typecheck → unit/component/contract category suites → headless product-shell smoke → optional live smoke), records logs under .e2e/results/, and writes .e2e/artifact.json in CTRF format with one entry per real evidence source.

Run the host-neutral gate with:

npm run e2e

The gate is self-contained in this repository. It does not depend on local agent skills or an external validator checkout.

Generated artifacts under .e2e/artifact.json and .e2e/results/ are runtime evidence and are intentionally ignored by git.

Test Categories

The source of truth for ordinary test classification is tests/catalog.json.

  • unit: pure logic tests with no Obsidian runtime, filesystem, process, or provider boundary.
  • component: plugin components exercised with controlled adapters, job managers, or Obsidian shims.
  • contract: provider protocols, CLI command shapes, exported test surfaces, and architecture invariants.
  • e2e: default project-local product-shell smoke. It installs the built plugin package into a disposable Vault filesystem and boots the packaged main.js against a recording Obsidian API shim. This checks package/install/lifecycle boundaries, but it is not a full Obsidian GUI run.
  • live: opt-in check against a real local Vault install. It verifies plugin files under .obsidian/plugins/parallel-reader/ and does not launch Obsidian, call a provider, or run GUI interactions. Run with TEST_LIVE=1 and set OBSIDIAN_VAULT_PATH when the default iCloud Vault path is not the target.

Useful commands:

npm run e2e
npm run test:unit
npm run test:component
npm run test:contract
npm run test:e2e
TEST_LIVE=1 npm run test:live

The .e2e gate emits one CTRF entry per real evidence source so risk-tag coverage maps to actual runs:

Entry Risk tags
build and typecheck boundary_io, wiring, regression
unit category regression
component category data_integrity, wiring, resource_lifecycle, regression
contract category contract, wiring, regression
headless product-shell e2e smoke boundary_io, wiring, resource_lifecycle, regression
live Vault install smoke (skipped unless TEST_LIVE=1) boundary_io, contract, regression

npm test remains a developer-facing convenience that runs the same build, typecheck, and category suites without the e2e/live legs.