docs: consolidate design documentation and standardize crate English

This commit is contained in:
2026-10-12 14:58:00 +09:00
parent a633a53274
commit 4efb0ace1f
404 changed files with 4556 additions and 11654 deletions
+13 -99
View File
@@ -1,106 +1,20 @@
# Workspace web UI
# Workspace Web
SvelteKit static SPA for the Yoi workspace control plane.
Workspaceの状態確認と操作を担当するstatic SPA。Backend projectionを表示し、認可と永続化はBackendへ委ねる。独立したWorkspace/Worker registryは持たない。
The frontend is intentionally static. Workspace authority, validation, and API behavior live in the Rust `yoi-server` backend.
## 実装の入口
## Toolchain
- `src/routes/+layout.svelte`: application shellとHeader/Sidebarの枠。
- `src/lib/workspace/sidebar/`: scope別navigationとoverride stack。
- `src/lib/workspace/console/`: Worker transcriptと入力編集。
- `src/lib/workspace/drive/`: Drive通信とdraft/receipt管理。
- `src/lib/workspace/markdown/`: 共有Markdown rendererとリンク検査。
- [`src/lib/generated/`](src/lib/generated/README.md): Rust契約からの生成物。
Dependencies are pinned in `deno.json` and `package.json`, with resolutions in `deno.lock`. Run `deno install --frozen` to reproduce the installed versions. The current toolchain is SvelteKit 3, Svelte 5, Vite 8, and Vitest 5. TypeScript is kept on 6.0.3 because SvelteKit 3.0.0 and svelte-check 4.7.6 do not yet declare support for TypeScript 7.
## 維持規則
SvelteKit and adapter settings live in `vite.config.ts`. Internal library imports use the `#lib/*` package subpath mapping with explicit file extensions, shared by Vite, TypeScript, and Deno. `tsconfig.json` extends `$app/tsconfig`; generated WASM JavaScript is consumed through its generated `.d.ts`, not checked as handwritten JavaScript. Deno-only tests under `test/` are type-checked by `deno task test`.
`src/app.css` はfont、cascade layer、semantic token、resetと基礎typographyを所有する。画面layoutと機能別styleは所有CSSまたはSvelte componentに置き、共通tokenを使う。
## Development
生成契約は手で編集しない。通常のWeb build/devもSvelteKit生成物を書き換えるため、稼働中のcheckoutを検証専用buildに使わない。
Use two terminals from the repository checkout.
Backend terminal:
```bash
cd web/workspace
deno task dev:backend
```
Frontend terminal:
```bash
cd web/workspace
deno task dev
```
The Vite dev server proxies `/api/*` to `http://127.0.0.1:8787`, so frontend hot reload works while the Rust backend serves the workspace API. Open the Vite URL printed by `deno task dev`.
If you want to run the backend from the repository root instead:
```bash
cargo run -p yoi-workspace-server --bin yoi-server -- serve --listen 127.0.0.1:8787
```
The backend reads Workspace records from the Yoi server DB at `<data_dir>/server/server.db`. Run `cargo run -p yoi-workspace-server --bin yoi-server -- init --workspace .` first when the server DB has not been initialized.
## Static build
Build the SPA:
```bash
deno task build
```
Static asset packaging is a deployment concern. Local development normally uses the Vite dev server proxy plus the Rust backend command above.
## Checks
```bash
deno task check
deno task test
deno task test:component
deno task build
```
## Design and architecture authority
- [`../../docs/development/ui-ux/design-language.md`](../../docs/development/ui-ux/design-language.md): visual and interaction language.
- [`../../docs/development/ui-ux/product-ux.md`](../../docs/development/ui-ux/product-ux.md): resource and navigation IA.
- [`../../docs/development/ui-ux/application-architecture.md`](../../docs/development/ui-ux/application-architecture.md): shell and nested override architecture.
- [`../../docs/development/ui-ux/visual-review.md`](../../docs/development/ui-ux/visual-review.md): implementer-owned visual validation.
This README owns frontend implementation guidance and concrete source paths. It does not redefine product or visual rules from those documents.
## CSS ownership
`src/app.css` is the global foundation and owns only:
- font imports;
- cascade layer order;
- semantic tokens and light/dark theme;
- reset and base element typography;
- global focus and text-selection behavior.
It must not own page layout, feature class selectors, table or definition-list layout, button variants, status presentation, helper spacing, or anchor color. Navigation, inline links, and action links own their color in the relevant component stylesheet.
Feature styles are owned by their implementation area:
- `src/lib/workspace/styles/workspace-pages.css`: Workspace main-content primitives.
- `src/lib/workspace/styles/tickets.css`: Ticket surfaces.
- `src/lib/workspace/styles/workers.css`: Worker surfaces.
- `src/lib/workspace/styles/settings.css`: Settings, Account, and form surfaces.
- `src/lib/workspace/styles/workspace-catalog.css`: Workspace catalog.
- `src/lib/workspace/sidebar/sidebar.css`: Sidebar components.
- Svelte-local styles: behavior-specific presentation that is not reused outside that component.
Use semantic tokens from `app.css`. Do not introduce component-local color, spacing, font, or z-index systems.
## Source map
- `src/routes/+layout.svelte`: root application shell and override contexts.
- `src/routes/w/[workspaceId]/+layout.svelte`: Workspace Header and Sidebar registration.
- `src/routes/w/[workspaceId]/settings/+layout.svelte`: Settings Sidebar registration.
- `src/lib/workspace/home/`: bounded, read-only work dashboard feeds and their presentation.
- `src/lib/workspace/settings/WorkspaceIdentitySettings.svelte`: Workspace-scoped name editing, public identity disclosure, and deletion confirmation.
- `src/lib/workspace/header/`: Header frame, context, and overrides.
- `src/lib/workspace/sidebar/`: Sidebar frame, scoped content, contexts, and override stack.
- `src/lib/workspace/markdown/`: shared safe Markdown parsing plus presentation-specific document renderers.
- `src/lib/workspace/ui/`: generic presentation components such as `Tooltip`, `Bevel`, and `BevelLine`.
- `src/routes/design-lab/workspace-web-ux/`: static Design Language showroom.
When one of these paths changes, update this source map in the same change. Stable architecture and UX authority remain in `docs/`; this map follows the current implementation.
視覚・操作の共通規則は[Design Language](../../docs/principle/design-language.md)、製品固有の画面構成と操作は[UX設計](../../docs/principle/ux-design.md)、画像と実装条件の検証は[目視確認の規則](../../docs/development/ui-ux/visual-review.md)に従う。
+6 -32
View File
@@ -1,35 +1,9 @@
# Generated frontend contracts
# 生成されたWeb契約
Checked-in files in this directory are generated API contracts. Do not edit them by hand.
このディレクトリのAPI型とvalidatorはRust契約からの生成物であり、手で編集しない。生成元とgeneratorは各ファイルのheaderに記録する。
## Repository list/detail/create API
- `repository-api.ts`: canonical OpenAPIから生成するRepository契約。
- `protocol.ts` / `protocol-validator.ts`: `protocol::subscription::SubscriptionFrame`から一緒に生成する型と受信検査。
- `legacy-server-api.ts`: 未分離の契約。新しいdomainを追加するときは、対象を限定した生成契約へ分ける。
`repository-api.ts` is the only TypeScript declaration authority for the Repository list, detail, and create request/response/error wire types. It is generated from the schema closure of the five Repository operations in the canonical `openapi/server-api.json` artifact. The generated header pins the in-repository generator name/version/options, canonical input path and digest, and output path.
Regenerate or verify it from the repository root:
```sh
cargo run -q -p server-api --example generate_repository_openapi_types
cargo run -q -p server-api --example generate_repository_openapi_types -- --check
```
The generator fails closed on unsupported or lossy OpenAPI constructs, including ambiguous nullable unions, external references, semantic `$ref` siblings, unimplemented ordinary schema keywords, unsupported enum literals/formats, and integer ranges that cannot be represented safely by JavaScript numbers. Its one explicit format mapping is canonical `uint64` to a nonnegative JavaScript safe `number`; the runtime parser enforces the same range. The legacy TypeScript generator imports the two shared Repository source projection types it still needs and no longer declares the migrated Repository list/detail types.
## Workspace subscription / Worker protocol
`protocol.ts` and `protocol-validator.ts` are generated together from the Serde/`schemars` closure of `protocol::subscription::SubscriptionFrame`. Rust DTOs and validation constants in `crates/protocol` remain the sole wire authority. The generator normalizes Serde defaults to the actual serialized required/nullable shape, tightens every supported Rust integer format to its JavaScript-safe wire range, and fails on an unknown integer format. The validator closes every generated object shape, rejects unknown tagged variants and unsafe integers, applies Rust-owned aggregate bounds to object keys as well as values, and mirrors the Browser-relevant `SubscriptionFrame::validate()` selector/payload checks. Rust-serialized compatibility fixtures are embedded for Browser regression tests. The Workspace multiplexer additionally checks live event payloads against its locally retained selector.
Inbound Browser frames only are validated: Browser-to-Server methods remain compile-time typed and are decoded plus semantically validated by the Rust server. Invalid inbound frames close the shared socket with a fixed, non-reflective diagnostic; the existing reconnect path clears routing state and requests fresh snapshots. A valid `subscription_closed` frame continues to isolate and resubscribe only that subscription.
Regenerate or verify both artifacts from the repository root:
```sh
cargo run -q -p protocol --example generate_typescript --features typescript
cargo run -q -p protocol --example generate_typescript --features typescript -- --check
```
The `protocol` crate tests also compare both checked-in files byte-for-byte with fresh generator output.
## Other generated contracts
The remaining files retain their generator command in their header. `legacy-server-api.ts` is transitional: new bounded domain slices should use a focused contract artifact instead of adding another API surface to it.
契約変更時はRustの生成元と出力を同じ変更で更新し、generatorの検査と互換fixtureで一致を確認する。Browser固有の受信処理は `../workspace/multiplexer.ts` が所有する。
@@ -1,3 +1,9 @@
/** Runtime管理ではbinding_idを観測した登録条件として送る。
* fingerprintはkey bytesの識別であり、bindingの再登録を識別する条件には使わない。
* revoke adapterは確認値とcurrentFingerprintの一致を検査するが、Serverへの条件は
* expected_binding_idである。画面は現在のfingerprintを両引数へ渡す。
* 接続テストの表示条件は呼出側の画面が現在bindingと照合する。
*/
import type {
CreateRemoteRuntimeRequest,
Diagnostic,
@@ -1,4 +1,9 @@
<script lang="ts">
// commitの条件は保存したbase_digestと各entryのexpected_digest。時刻や要求順では
// 編集元の内容を特定できないため、成功時だけ返されたsnapshotを新しいbaseにする。
// Server拒否時はdraftを残し、reload/reapplyを明示的な判断にする。
// 診断は非abortかつ解析対象tree digest一致の場合だけ表示する。content条件と
// 非同期requestの有効性は別に検査し、遅い解析を現在のsourceの診断として出さない。
import { onMount } from "svelte";
import DecodalSourceEditor from "#lib/workspace/settings/DecodalSourceEditor.svelte";
import {
@@ -1,3 +1,8 @@
/** Rust契約に従うconfig treeの通信と応答検査。
* tree digestはsource、projection digestは評価結果、contract fingerprintはtoolchain条件を指す。
* ConfigProjectionValidatorはstatic template catalogの検査方針であり、鮮度tokenではない。
* Browserの解析成功はServerのcommit受理を代替しない。
*/
import type {
ConfigCommitRequest,
ConfigContentType,
@@ -1,3 +1,7 @@
/** Session snapshotとprotocolイベントからtranscriptの表示projectionを構築する。
* Overview/Normalは表示だけを変え、保存履歴やWorker状態の根拠を変更しない。
* 実行状態はWorker snapshotで更新し、stream表示とWebSocket接続状態から推測しない。
*/
import type {
Alert,
CommandEvent,
@@ -1,60 +1,9 @@
# Worker Drive grant controls
# Worker Drive grants
`WorkerDriveGrants.svelte` is embedded in the existing Workers page. The page supplies its current `workspaceWorkersStore().catalogWorkers` projection; this component neither discovers Workers nor maintains a registry.
既存Workers画面内のDrive grant管理を担当する。Worker一覧と管理permissionは親画面のBackend projectionを使い、独自のWorker registryやProfile編集機能は持たない。
## Integration interface
- `WorkerDriveGrants.svelte`: Worker選択、grant表示、作成と取消しの状態管理。
- `api.ts`: 認証済みgrant APIと応答検査。
- `WorkerDriveGrants.browser.spec.ts`: 実componentを使うHTTP fixture検証。
```ts
{
workspaceId: string;
workers: Pick<Worker, "runtime_id" | "worker_id" | "display_name" | "label">[];
canManage: boolean;
workersReady?: boolean; // defaults to true for standalone use
}
```
The page maps `canManage` to `workspace.permissions.manage_runtimes` (the current Backend owner settings permission) and `workersReady` to `catalogReady && !catalogRefreshing`. Non-owners have no grant surface or grant requests. Backend owner authorization remains authoritative on every request. Profile Drive tool enablement is separate and is not edited here.
`api.ts` is the owner-controlled grant transport adapter using generated `drive-api.ts` DTOs. It keeps grant administration separate from ordinary content access:
- `listDriveGrants(workspaceId): Promise<DriveGrantResponse[]>` — fetch **all** grant pages (200/page, bounded to 100 pages); reject incomplete, foreign-Workspace, duplicate, unordered or cyclic results instead of silently truncating.
- `createDriveGrant(workspaceId, DriveGrantCreateRequest): Promise<DriveGrantResponse>`.
- `revokeDriveGrant(workspaceId, DriveGrantResponse): Promise<DriveGrantResponse>`.
- `DriveGrantError` with `outcome: "not_committed" | "unknown"`.
- Generated `DriveAccess` / `DriveGrantResponse` type exports.
Mutation success must validate Workspace/Runtime/Worker identity and the requested resulting state. HTTP bodies are bounded; transport loss, malformed success and unclassified failures are unknown mutation outcomes. No Worker credentials or transport identity headers are sent; requests use current browser same-origin authentication and bypass caching.
Workspace, selected Worker, catalog membership/readiness, permission and component lifetime fence asynchronous results. Workspace switches clear selection; unchanged catalog identities do not clear pending mutations. Active grants match **both** Runtime and Worker IDs. An existing active grant must be revoked before another access level is created. Unknown outcomes remove actionable state until an explicit authority refresh, never automatic mutation retry.
## Narrow validation
From `web/workspace`:
```sh
deno task test:component src/lib/workspace/drive-grants/WorkerDriveGrants.browser.spec.ts 'src/routes/w/[workspaceId]/workers/workers-page.browser.spec.ts' 'src/routes/w/[workspaceId]/workers/workers-restore-integration.browser.spec.ts'
deno run -A npm:svelte-check@4.7.6 --tsconfig ./src/lib/workspace/drive-grants/tsconfig.check.json
# Full integration check (also includes sibling-owned work):
deno task check
```
Recorded result: 21 grant tests plus 29 existing Workers tests passed. Final parent integration `deno task check` reported zero errors/warnings, and the complete component suite passed 301 tests in 32 files. Intermediate test-only `ByRoleOptions` errors were corrected before final validation.
The component tests exercise actual rendered controls with HTTP-boundary fixtures, including pagination, same Worker ID on different Runtimes, owner gating, scope switches, removal, single-submit behavior, read-only/read-write creation, revocation, denial and unknown outcomes. The existing Workers tests cover retention/restore/catalog regressions.
## Visual evidence
The development-only `tools/web-ux/drive-grants/visual-review.ts` runner uses the real Workers route and application shell with loopback browser API fixtures. It creates no real Backend, Runtime, Worker, account or grant state. It lives outside production Web source and is independently Deno-checked:
```sh
# From repository root, in the dev shell:
deno run --check --config tools/web-ux/deno.json -A tools/web-ux/drive-grants/visual-review.ts after
```
`before` mode must run against the original Workers page source. For the recorded baseline, the original page was temporarily restored from the read-only Git source and the implemented page restored in `finally`; Git/index/history were not changed.
Evidence: `target/web-ux/t724-drive-grants/{before,after}/review-context.json` and sibling PNGs. Contexts record screenshot hashes, Workers page source hash, browser version, accessibility, visible/browser/request errors and document overflow. The after context also records component/API source hashes and the runner checks grant controls for viewport clipping.
Reviewed owner/non-owner, light/dark, 1440/768/390 px; active, empty/create form, loading, deliberately failed list, long labels/identifiers/errors. The before bundle has 24 captures and the after bundle has 42. `compare-{theme}-{width}.png` and `states-{theme}-{width}.png` contact sheets in the same artifact root were opened by the implementer, along with individual captures.
Finding fixed: the pre-existing Worker table widened the page's grid track and clipped new grant controls. The page now constrains its grid and gives the table a named keyboard-accessible local scroll region. Long native-select labels have a full identity disclosure. No unexpected browser errors or document overflow were observed; intentional HTTP 503 console errors belong to the error fixture (and remain in the cumulative diagnostics of its subsequent loading capture). Other pre-existing Worker table presentation is unchanged.
変更時はcomponentとAPI境界のfixture検証を保ち、Worker catalogの所有者をこのcomponentへ移さない。
@@ -1,4 +1,7 @@
<script lang="ts">
// 親Workers画面のcatalogとpermissionを使い、grantはRuntime/Workerの組で照合する。
// catalog readinessは新規操作を止めるが、同じidentityへの送信済み変更を破棄しない。
// 不明な変更結果は明示的refreshまで操作不可とし、自動再試行しない。
import { untrack } from 'svelte';
import type { Worker } from '#lib/workspace/sidebar/types.ts';
import { createDriveGrant, DriveGrantError, listDriveGrants, revokeDriveGrant, type DriveAccess, type DriveGrantResponse } from './api.ts';
@@ -1,3 +1,7 @@
/** content accessとは別のowner管理API。browserのsame-origin認証を使う。
* grant一覧は全pageの順序・重複・Workspace一致を検査し、不完全な結果を正常一覧にしない。
* 変更応答は要求identityと結果状態を照合し、通信断や不正な成功応答はunknownにする。
*/
import type {
DriveAccess,
DriveApiError,
@@ -7,7 +11,6 @@ import type {
} from "#lib/generated/drive-api.ts";
import { readBoundedJson, workspaceApiPath } from "#lib/workspace/api/http.ts";
// Owner-controlled grant transport, separate from ordinary Drive content access.
export type { DriveAccess, DriveGrantCreateRequest, DriveGrantResponse };
export class DriveGrantError extends Error {
constructor(message: string, readonly outcome: "not_committed" | "unknown") {
@@ -1,7 +1,6 @@
<script lang="ts">
// No Markdown image triggers an automatic network request. This includes external
// tracking pixels, API URLs and cross-Workspace images. Open an authorized node URL
// explicitly to use the bounded raster viewer.
// Markdown画像は外部tracking pixel、API、別Workspaceを含めて自動取得しない。
// 代替textだけを示し、明示的に開いた認証済みDrive URLでbounded raster表示を行う。
let { text = '', title }: { text?: string; title?: string } = $props();
</script>
<span class="drive-inline-image" {title}>[Image: {text || 'unnamed'} — open its Drive URL to view]</span>
@@ -1,4 +1,7 @@
<script lang="ts">
// optional node routeでcontrollerを共有し、draftとreceiptはpage sessionだけに保持する。
// Driveから離れる際は破棄を確認する。権限拒否はBackend応答から表示し、Web独自ACLは作らない。
// partial textは保存させず、image Object URLは切替・破棄時に解放する。
import { onDestroy } from 'svelte';
import { beforeNavigate } from '$app/navigation';
import { createDriveClient, driveDownloadUrl, DRIVE_FILE_MAX_BYTES, DRIVE_RESPONSE_MAX_BYTES, type DriveEntry, parseDriveDecimal } from '#lib/workspace/drive/api.ts';
@@ -1,3 +1,6 @@
/** previewは宣言されたmedia typeで選び、拡張子からHTML/SVG等の実行可能な表示を許可しない。
* Markdown/plain textとrasterだけを対象とし、その他はdownloadに限定する。
*/
import type { DriveEntry } from "#lib/generated/drive-api.ts";
export { DRIVE_TEXT_MAX_BYTES } from "#lib/workspace/drive/api.ts";
+7 -1
View File
@@ -1,3 +1,8 @@
/** 認証済みDrive APIの境界。node IDはJavaScriptの整数精度を超えるため十進文字列で保持する。
* Web latest routeとAPI download URLを分け、URLやIDの所持を認可として扱わない。
* bounded bodyを検査し、送信後の通信断や不正な成功応答は結果不明としてreceipt照会へ渡す。
* uploadはraw Blobで送るが、SHA-256計算には上限付きArrayBufferを使う。
*/
import type {
DriveApiError,
DriveEntry,
@@ -516,7 +521,8 @@ export function createDriveClient(fetchFn: typeof fetch = fetch): DriveClient {
),
image: async (ws, entry, signal) => {
parseDriveEntry(entry, ws);
// Do not render active SVG or HTML as a preview.
// 観測したlast_mutation_idにdownloadを固定し、取得中の置換をlatestへの追従で隠さない。
// SVGやHTML等の実行可能な形式はpreviewにしない。
if (
!/^(image\/(png|jpeg|gif|webp))$/.test(entry.content_type ?? "") ||
entry.size === null || entry.size > DRIVE_RESPONSE_MAX_BYTES
@@ -1,3 +1,12 @@
/** Drive page session内のdraftとreceiptをWorkspace/node単位で保持する。
* 選択世代で遅延応答を除外し、A→B→Aでも過去の応答で表示や保存先を変えない。
* draftは読取時のlast_mutation_idを保持し、競合でも自動rebase・再送をしない。
* mutation IDは実際の確定要求を識別する。rename/moveや同じbytesへの復帰を区別するため、
* content digestで代替しない。選択世代はlocal応答の有効性だけを表し、Serverの変更条件ではない。
* 保存確認は送信後の編集を残す。結果不明のreceiptがあるentryへの新規変更は止める。
* 不明結果は同じrequest IDで照会する。新しいIDでの再送は確定済みの副作用を重複させうる。
* receipt照会のuncommittedは未確定であり、失敗の証明ではない。browser reloadでの保持はしない。
*/
import type { DriveMutationResponse } from "#lib/generated/drive-api.ts";
import {
createDriveClient,
@@ -66,10 +75,7 @@ function message(error: unknown): string {
? error.message
: "Drive request could not be completed";
}
/** A subscribable snapshot store; Svelte consumers may use `$controller` directly.
* All asynchronous publication is fenced by selection generation. Aborting a
* write does not establish failure: its receipt is retained for reconciliation.
*/
/** Svelte側からも購読できる状態store。 */
export class DriveController {
private value = empty();
private listeners = new Set<(state: DriveControllerState) => void>();
@@ -1,4 +1,5 @@
<script lang="ts">
// 本文の共有parserを使い、表示別rendererでもraw HTML拒否とリンク検査を上書きできない。
import SvelteMarkdown, {
buildUnsupportedHTML,
type Renderers,
@@ -1,4 +1,8 @@
// Workspace resource links are navigation, never bearer credentials or fetch targets.
/** Markdownのリンク先を明示的resource routeか外部HTTP(S)へ限定する。
* Workspace contextがある場合、resource routeはそのWorkspaceだけを許可する。
* URLはnavigation用であり、bearer credentialや自動fetch先ではない。
* 任意の相対path、API path、protocol-relative URL、userinfo付き外部URLは拒否する。
*/
export const MARKDOWN_WORKSPACE_CONTEXT = "yoi-markdown-workspace";
export type MarkdownWorkspace = () => string;
export type MarkdownLinkTarget = { href: string; external: boolean };
@@ -214,6 +214,10 @@ export async function createSubjektivSubject(
}
}
/** 空本文も含めて、観測したexpected_behavior_mdをそのまま変更条件に使う。
* 成功応答の本文が要求と異なる場合は結果不明とし、自動再試行しない。
* 保存の確認とWorker履歴への適用は別の操作である。
*/
export async function updateSubjektivSubjectBehavior(
fetchFn: typeof fetch,
workspaceId: string,
@@ -964,6 +968,9 @@ function parseMemorySourceEvidenceRef(
return result;
}
/** immutable change_idの一覧をServer順で保持する。
* IDは履歴参照用であり、数値への変換やID順のsortで時系列を作らない。
*/
export function parseSubjektivMemoryListChangesResponse(
value: unknown,
expectedMemoryId?: string,
@@ -1,3 +1,8 @@
/** reviewの有効性はsubject_refと現在source refの一致で判断する。
* 取消し済みreviewを除き、Serverが渡したthread順で有効なeventを選ぶ。
* 新しい応答やtarget移動だけでは別sourceへの承認にならない。merged表示は
* Backendが検証したimmutable integration evidenceを使い、新しいlive観測で上書きしない。
*/
import type {
TicketEvidenceSummary,
TicketMergeRequestSummary,
@@ -1,3 +1,9 @@
/** Workspaceごとに共有するsubscription transport。
* 受信frameをRust生成validatorと保持中selectorの両方で検査する。
* 不正frameは共有socketを固定診断で閉じ、再接続時にroutingを消してsnapshotを取り直す。
* 正常なsubscription_closedは対象subscriptionだけを終了または再購読する。
* 送信Methodの実行時decodeと意味検査はRust Serverが所有する。
*/
import { browser } from "$app/env";
import type {
EventSubscriptionSelector,
@@ -1,4 +1,7 @@
<script lang="ts">
// navigation内容だけをscrollさせ、下部の表示mode controlは到達可能なままにする。
// hover previewはkeyboard focusでも保持し、折りたたんだ内容はinertでtab順から外す。
// Mobileの開閉はHeaderから行うため、狭い画面で隠れたSidebar内に開閉操作を閉じ込めない。
import { onDestroy, onMount, type Snippet } from 'svelte';
import { on } from 'svelte/events';
import Bevel from '#lib/workspace/ui/Bevel.svelte';
@@ -1,4 +1,7 @@
<script lang="ts">
// 日常のresource navigationをWorkspace scopeに置く。管理対象はSettingsに分ける。
// 子overrideはnavigation部分だけを置き換え、Workspace shortcut headerを保持する。
// identityと読み込み失敗は親のBackend projectionを表示し、URLから正常状態を作らない。
import type { Snippet } from 'svelte';
import './sidebar.css';
import { workspaceRoute } from '#lib/workspace/api/http.ts';
@@ -1,3 +1,7 @@
/** Header/Sidebarのlayout登録を新しい順に表示するstack。
* cleanupは登録固有のIDだけを除き、重複cleanupや古いlayoutの破棄で新しい内容を消さない。
* active登録がなくなればnullを通知し、呼出側のfallbackへ戻す。
*/
export type OverrideDisposer = () => void;
export type OverrideStack<T> = {
@@ -1,4 +1,7 @@
<script lang="ts">
// 単色の境界だけを所有し、背景と操作の意味は内側のsemantic childへ委ねる。
// 隣接領域では境界となる辺だけを描き、無効な辺の角丸も消して境界の途切れを避ける。
// controlのfocus表示は外枠へ移さず、childの入力・buttonとしての動作を保つ。
import type { Snippet } from 'svelte';
type Props = {
@@ -1,4 +1,6 @@
<script lang="ts">
// 開いた領域のseparator。線だけに端の余白を持たせず、親layerの本文と端を揃える。
// 入れ子の余白は親が領域全体へ与える。装飾線だけは読み上げ対象から外す。
export type BevelLineDirection = 'x' | 'y';
type Props = {
@@ -1,4 +1,8 @@
<script lang="ts">
// hoverの遅延は通過時の表示を抑え、keyboard focusでは即時に補助説明を示す。
// childrenへ渡すidをtriggerのaria-describedbyに使い、Escapeでもfocusは動かさない。
// 内容は操作controlを含まないtextに限定する。判断に必須の状態・制約はここへ隠さず、
// touchでもTooltip以外から読めるようにする。fixed配置はscroll時にも対象位置へ合わせる。
import { onDestroy, onMount, tick, type Snippet } from 'svelte';
type Placement = 'top' | 'bottom';
+5
View File
@@ -1,4 +1,9 @@
<script lang="ts">
// application shell、Header、Sidebar外枠はrootだけが描画する。
// scope layoutは内容をoverrideへ登録し、pageはmainの内容だけを所有する。
// navigationの構成はWorkspace identityやpermissionの根拠にはしない。
// Header下辺とSidebar右辺だけで領域境界を示し、viewport外周に線を重ねない。
// MobileはSidebarがHeader下を占有する間mainをinertにし、隠れた内容へfocusを入れない。
import { page } from '$app/state';
import { setContext } from 'svelte';
import { MediaQuery } from 'svelte/reactivity';
@@ -1,4 +1,6 @@
<script lang="ts">
// 認証不要のstatic fixtureでもroot shellとnested overrideのlifecycleを再利用する。
// live resource一覧だけを同じscopeのfixtureへ置き換え、独自shellやscope切替controlは作らない。
import { page } from '$app/state';
import { setContext } from 'svelte';
import HeaderOverride from '#lib/workspace/header/HeaderOverride.svelte';
@@ -1,4 +1,7 @@
<script lang="ts">
// root slotへWorkspace内容を登録し、子layoutには別のSidebar controllerを提供する。
// Settings等の子はこのslotだけを差し替えるため、Workspace shortcut headerが残る。
// Workspace切替と破棄時に旧subscriptionを解放し、別Workspaceのprojectionを混ぜない。
import { onDestroy, setContext } from 'svelte';
import { page } from '$app/state';
import HeaderOverride from '#lib/workspace/header/HeaderOverride.svelte';
@@ -1,4 +1,9 @@
<script lang="ts">
// identity、current Worker、Committed Memory、生成contextの利用可否を先に示す。
// current WorkerはBackend singleton projectionであり、過去のSession帰属から推測しない。
// behaviorは利用者が管理する本文、surfaceはMemoryからの生成物として分ける。
// ready-empty/ungenerated/stale/failedとrequest failureを区別し、surfaceの現在性を
// 実行中Workerの履歴へ反映済みであることの証明には使わない。診断値は詳細へ分離する。
import { untrack } from 'svelte';
import DocumentMarkdown from '#lib/workspace/markdown/DocumentMarkdown.svelte';
import { formatDate, workspaceRoute } from '#lib/workspace/api/http.ts';
@@ -1,3 +1,7 @@
/** Subject、resident surface、Committed Memoryの一ページを独立した結果として読む。
* surface未生成や候補の存在からCommitted Memory件数を推測せず、全件走査もしない。
* 一つの読み込み失敗を他のresourceの空状態へ置き換えない。
*/
import { loadJson, workspaceApiPath } from "#lib/workspace/api/http.ts";
import {
MEMORY_API_LOAD_POLICY,
@@ -1,4 +1,6 @@
<script lang="ts">
// current/historicalはchange_idとcurrent_change_idの一致で区別する。
// 本文・evidenceの続きも同じimmutable changeへ固定し、現在版の内容を混ぜない。
import DocumentMarkdown from '#lib/workspace/markdown/DocumentMarkdown.svelte';
import { formatDate, workspaceRoute } from '#lib/workspace/api/http.ts';
import type {
@@ -1,4 +1,6 @@
<script lang="ts">
// Settings navigationだけをWorkspaceの子slotへ登録する。
// 親navigationを複製せず、さらに深いscopeへ独立したoverride controllerを渡す。
import { page } from '$app/state';
import { setContext } from 'svelte';
import SettingsSidebar from '#lib/workspace/sidebar/SettingsSidebar.svelte';
@@ -165,6 +165,8 @@
function currentTestResult(
runtime: WorkspaceRuntimeResource,
): RuntimeConnectionTestResponse | undefined {
// 登録し直したRuntimeへ古い接続テストを流用しない。key一致やchecked_atではなく
// 現在のWorkspaceとbinding identityを表示条件にする。
const result = testResults[runtime.runtime_id];
return result?.workspace_id === data.workspaceId &&
result?.binding_id === runtime.management?.binding?.binding_id
@@ -1,4 +1,7 @@
<script lang="ts">
// 接続テストはWorkspace/Runtime/現在bindingが一致する結果だけを表示する。
// 同じpublic keyでも再登録したbindingへ古い成功を適用しない。route世代は遅延応答の
// 除外用であり、binding identityやBackendの変更受理条件を代替しない。
import { goto, invalidateAll } from '$app/navigation';
import type {
RevokeRuntimeTrustKeyRequest,
@@ -1,4 +1,6 @@
<script lang="ts">
// workflow stateのlaneを横方向に比較するboard。狭い画面でもlaneを縦に分断せず、
// tickets.cssの局所横scrollを使う。key、title、blocker/attentionを判断の入口にする。
import { goto } from "$app/navigation";
import { untrack } from "svelte";
import type { ApiResult } from "#lib/workspace/api/http.ts";
@@ -1,4 +1,6 @@
<script lang="ts">
// transcriptの表示対象と操作対象を分離する。direct SubWorkerを閲覧しても、
// Composerとrun controlはrouteの親Workerへ送る。表示切替で操作権限を変えない。
import { invalidateAll } from "$app/navigation";
import { tick, untrack, type SvelteComponent } from "svelte";
import { prefersReducedMotion } from "svelte/motion";
+6 -49
View File
@@ -1,52 +1,9 @@
# T-724 browser fixture validation
# Drive Browser fixture
These tests serve the real static production Web shell against a loopback, in-memory API fixture. They are **not actual Backend/DB/LocalFileSystem authorization or round-trip evidence**. The parent owns the separate real API checks.
production static shellをloopbackのin-memory API fixtureに接続し、描画、操作、遅延応答、draft保持を検証する。Backend/DB/blob storageの認可を証明するテストではない。
## Runtime prerequisites
- `fixture-api.test.ts`: fixtureとWeb parserの契約一致。
- `drive.browser.test.ts`: production画面の操作と要求の整合。
- `responsive.browser.test.ts` / `capture-visual.ts`: responsive検査と画像・診断の保存。
Deno and Playwright Chromium must be available. The server binds loopback only and owns/cleans up its shared Home fixture subprocess. Tests use an ephemeral port and independent fixture state; no real workspace data, credentials, git operations, environment test switches, or UI/CSS fixture branches are used.
The parent must confirm UI readiness before the production build and browser run. Tests intentionally never build automatically.
```sh
# Narrow API-fixture compatibility checks (safe before UI readiness)
deno test --config web/workspace/test/drive-browser/deno.json --allow-read web/workspace/test/drive-browser/fixture-api.test.ts
# After explicit parent UI-ready signal and successful production build only:
deno test --config web/workspace/test/drive-browser/deno.json --allow-env --allow-net --allow-read --allow-write --allow-run --allow-sys web/workspace/test/drive-browser/drive.browser.test.ts
# Responsive audit, with optional frozen production site and artifact suffix:
deno test --config web/workspace/test/drive-browser/deno.json --allow-env --allow-net --allow-read --allow-write --allow-run --allow-sys web/workspace/test/drive-browser/responsive.browser.test.ts -- web/workspace/.svelte-kit/t724/verified-build/site final-reviewed
# Official tools/web-ux bundles; no build is performed by this runner.
deno run --config web/workspace/test/drive-browser/deno.json --allow-env --allow-net --allow-read --allow-write --allow-run --allow-sys web/workspace/test/drive-browser/capture-visual.ts before <unique-run-suffix>
deno run --config web/workspace/test/drive-browser/deno.json --allow-env --allow-net --allow-read --allow-write --allow-run --allow-sys web/workspace/test/drive-browser/capture-visual.ts after <unique-run-suffix> [workdir-relative-production-site]
```
## Fixture API
Start `tools/web-ux/drive-fixture/server.ts <port> <build-root>` with `--allow-net --allow-read --allow-run --allow-env`. It extends the shared Home/settings API fixture through a loopback proxy and implements Drive root/list/metadata/search/read-text/read-chunk/download/mutate/upload/request-status/grants APIs. Response wire types derive from generated Drive DTOs; current client parsers are exercised by the fixture compatibility tests.
- Root ID `9007199254740993` tests lossless decimal references.
- `2`: folder 資料; `3`: Markdown README; `4`: text inside folder 2.
- `5`: valid synthetic 1200×800 `landscape.png` (16,813 compressed bytes), generated as real binary PNG data by `tools/web-ux/drive-fixture/raster.ts`; `6`: empty text; `7`: undecodable PNG; `8`: SVG download-only; `9`: text exceeding 64 KiB; `10`: long Japanese name; `11`: valid 64 KiB NUL text whose escaped JSON exceeds 256 KiB but stays below the separate 512 KiB JSON bound.
- `home-member` and `*readonly*`: reads succeed, mutations are typed HTTP 403. No metadata permission flag is invented. The UI reacts to a denied operation, not speculative permission inference.
- `*denied*`: typed HTTP 403 root/read; `*offline*`/`home-error`: typed HTTP 503; `*empty*`: empty successful root list; `*paged*`: 240 additional nodes.
- `POST /__fixture/fault` JSON `{workspace, mode}`: one-shot `conflict` or committed `unknown` mutation response; persistent `image_error` binary fetch failure.
- `home-owner`/`home-member`/`home-long`: representative authoritative Worker catalogs; REST and subscription projections come from the same generated-shape records. `home-long` includes long display names and opaque Runtime/Worker IDs. `workers-error` intentionally fails catalog reads with HTTP 503.
- `GET /__fixture/log`: observable API request IDs/methods/paths/node IDs/CAS observed committed requests for identity and no-resend assertions.
- `POST /__fixture/reset`: fresh in-memory state.
Request delay/loss tests intercept the API boundary with Playwright and synchronize on gates, not guessed sleeps. They let the fixture commit before dropping/holding the response, then verify receipt query without blind upload retry.
## Visual evidence
Preserved production baseline: `.svelte-kit/t724/before-build/{site,output,build.log}`. Official bundles live below `.svelte-kit/t724/visual/`. Each contains screenshots, console/request/page diagnostics, accessibility snapshots, screenshot hashes, source commit/dirty context, and `review-context.json`.
Home/sidebar and Workers are captured under identical owner/member/error/empty/long conditions, light/dark at 1440/768/390/320. After captures add Drive owner/member/empty/error/denied/paged/Markdown/image/image-error/truncated surfaces, pinned rename/replace observed committed request forms, and owner grant selection/read-only/read-write/revoked states. Expected injected 503/403 diagnostics and superseded breadcrumb metadata aborts remain in official context; `diagnostic-disposition.json` explicitly separates unexpected diagnostics. CLI `completed-with-errors` is not relabeled a visual pass.
The production shell scrolls `main` internally, so `fullPage` does not expand that scroll panel. Capture points use ordinary keyboard focus to show the actual form or the top denial state; no CSS/DOM screenshot override is applied. The responsive audit separately records document/main/table-region geometry, visible keyboard focus, and page errors across the full theme/viewport matrix. Raster checks wait for actual decoding, assert natural dimensions 1200×800, preserve the 3:2 aspect ratio, and constrain the rendered box by both the available width and 60vh height at all four widths/both themes.
The Drive browser suite also exercises the file-browser redesign at 1440/768/390/320px in light/dark themes: menu placement, native-dialog focus and Escape restoration, folder creation, search, and destination-folder navigation. Screenshots are written to `.svelte-kit/drive-redesign/` for the list, New menu, creation dialog, Markdown preview, and move dialog. Component tests cover failed/paged destination reads, exclusion of files and the moving folder itself, and pinned mutation observed committed requests. These checks use the same fixture boundary, not a live Backend.
Parent and reviewer must open images and inspect context before asserting visual acceptance. In particular, a successful capture command is not sufficient and HTTP 200 does not excuse visible UI errors.
fixtureは実Workspaceや資格情報を使わず、所有subprocessを片付ける。テストは自動buildを行わない。検証対象のstatic生成物を明示し、画像と診断を確認してから視覚面の合否を判断する。実HTTP/storageの保証は [別harness](../drive-real-api/README.md) で検証する。
+4 -44
View File
@@ -1,47 +1,7 @@
# Real Drive API/Web roundtrip (not the browser fixture)
# Drive実API roundtrip
This harness uses a fresh RAII temporary directory, real Server SQLite records, FeatureStorage Drive nodes and `object_store::local::LocalFileSystem` blobs. It creates a Workspace through T-717's actual repositoryless `/api/workspaces` endpoint. No repositories, user's data, live Server, environment-variable test configuration, Tools or WIP are involved.
Rustの `drive_web_roundtrip_tests` が起動する隔離loopback Serverへ、`roundtrip.ts` がproduction Web adapterで接続する。実SQLite、FeatureStorage、LocalFileSystemを使い、認可、保存、receipt、競合、grant取消しを検証する。
The ordinary Rust test exercises loopback HTTP signed Worker ingress: explicit read-only/read-write grants, rejection of read-only writes, Worker-created bytes visible through Web/user API, and immediate grant revocation (even when the request also carries an owner's bearer token). Only the Runtime worker-spawn boundary uses the existing deterministic workdirless fixture runtime.
認証情報とWorkspace identityは親harnessからstdinで受け取り、argvやログには出さない。実ユーザーデータと稼働中Serverは使わない。Denoプロセスは接続先を指定loopback originへ限定する。
The explicit process test starts a loopback Axum Server and launches Deno against it. `roundtrip.ts` imports the production `src/lib/workspace/drive/api.ts` adapter, not a copy or mock. Its typed `fetchFn` resolves relative paths only to the bound loopback origin and adds fixture bearer authorization. Tokens travel over stdin, not command-line arguments or logs; Rust failure diagnostics defensively redact both fixture bearer tokens. Deno has network permission only for the exact loopback port, uses no npm dependencies, and runs with `--cached-only`. Each listener is abort-on-drop, child processes are kill-on-drop, and the child has a 60-second upper timeout, without sleeps or readiness polling.
Coverage: Worker file list/read, Japanese folder/Markdown names, create/read/edit/download, empty files, actual PNG upload/authenticated image/download and binary update, publication receipt lookup, paged list, two authenticated accounts racing a common observed committed request (one commit/one typed conflict, no hidden retry), stable latest URL through rename and move, deleted URL and same-name recreation, and unauthorized latest URLs. The exact Workers-page `drive-grants/api.ts` adapter also lists persisted grants, creates both access levels, revokes them and re-reads durable state, and rejects member administration. Its global browser fetch is temporarily origin/auth-bound in this isolated child; network responses are never mocked. This tests real authenticated HTTP with test bearer credentials, not a Passkey/cookie browser login or a full Runtime process. UI dirty-draft retention, delayed response handling, visual review and browser cancellation belong to the **separate browser fixture**, not this API test.
## Registration
The inline `mod tests` block in `crates/workspace-server/src/server.rs` registers the module alongside the existing Drive API tests:
```rust
mod drive_web_roundtrip_tests;
```
No product routing modification is needed. The scoped production router is cached by the harness without starting unrelated Orchestrator hook tasks; production server ingress, authorization and API/storage handlers still run.
## Run
From the repository root:
```sh
cargo test -p yoi-workspace-server --lib drive_web_roundtrip_tests
cargo test -p yoi-workspace-server --lib drive_web_roundtrip_tests -- --ignored
```
The second command requires Deno on PATH. Its ignored marker is an explicit process/E2E prerequisite, not an environment-variable gate or silent fallback. An absent Deno fails the explicit test. The ordinary real HTTP test does not require Deno.
The script is harness-only: it receives fresh credentials and Workspace identity from the parent over stdin; do not invoke it against a live Server. Type-check it without starting the Server:
```sh
deno check --config web/workspace/test/drive-real-api/deno.json \
web/workspace/test/drive-real-api/roundtrip.ts
```
## Validation evidence
Validated against the production Server endpoints and Web adapter, not the browser mock routes:
- `cargo test -p yoi-workspace-server --lib drive_web_roundtrip_tests -- --test-threads=4`: **1 passed, 1 explicitly ignored** (the process prerequisite).
- `cargo test -p yoi-workspace-server --lib drive_web_roundtrip_tests -- --ignored --test-threads=4`: **1 passed**; the actual Deno adapter process completed against real SQLite/LocalFileSystem HTTP.
- `cargo test -p yoi-workspace-server -- --test-threads=4`: **693 library tests passed, 1 ignored; 11 binary tests passed; doc-tests passed**.
The repositoryless fixture was adjusted to retain the production runtime trust gate's exact normalized binding snapshot and to scope the reusable Runtime observation to the newly bootstrapped Workspace. Neither fix changes the API, Drive authorization policy, Tools, WIP, or browser fixtures.
Runtime spawn境界はfixtureであり、Passkey/cookie loginや画面操作のE2Eではない。画面のdraft保持、キャンセル、視覚面は [Browser fixture](../drive-browser/README.md) が担当する。親Rust harnessとproduction adapterの両方を維持し、通信応答をmockへ置き換えない。
@@ -1,5 +1,5 @@
// Invoked only by the Rust loopback harness. No mocked responses, live server,
// browser fixtures, environment variables, or bearer credentials in argv/logs.
// Rust loopback harness専用。production adapterを実HTTPで検証し、応答をmockしない。
// fixture認証情報はstdinから受け取り、argvやログへ出さない。画面操作の検証とは分離する。
import {
createDriveClient,
type DriveClient,
+5 -90
View File
@@ -1,93 +1,8 @@
# Optional initial repository validation (T-717 Web portion)
# Repository任意作成の視覚検証
These scenarios use the production static Workspace build and the existing
`tools/web-ux` capture/process harness. The loopback proxy only extends the shared
Home fixture's API responses for empty Worker lists and launch options; it does
not replace the application shell, styles, or components. No real Workspace,
account, repository, Runtime, or Worker is created.
production static Workspace画面と共有 `tools/web-ux` harnessを使い、RepositoryなしのWorkspace作成、catalog、Worker起動を検証する。loopback proxyはAPI fixtureだけを拡張し、shell、style、componentはproduction実装を使う。
## Run
- `optional-repository.json`: 空Workspaceとcatalogの表示条件。
- `optional-repository-interactions.json`: 作成操作と意図した拒否応答。
From `web/workspace`, with the repository's pinned Chromium available:
```sh
deno task build
deno task test:browser:empty-workspace
```
The browser test covers light/dark at 1440, 768, 390, and 320px: optional Git
native validation, opting out after entering repository values, null creation
response/navigation, zero-repository catalog reopening, normal embedded Worker
submission without Workdir or Ticket assignment, and remote Runtime Workdir
requirements. It uses dynamically allocated loopback ports and the existing
owned-process cleanup harness. Screenshots and logs are ignored artifacts under
`.svelte-kit/t717/browser`.
From `tools/web-ux`:
```sh
deno task web-ux capture \
--scenario ../../web/workspace/test/visual-review/optional-repository.json \
--output ../../web/workspace/.svelte-kit/t717/visual --run-id empty-workspace
deno task web-ux capture \
--scenario ../../web/workspace/test/visual-review/optional-repository-interactions.json \
--output ../../web/workspace/.svelte-kit/t717/visual --run-id creation-interactions
```
The interaction scenario intentionally rejects creation with HTTP400. Capture
exit status 2 and the recorded request/console/visible validation errors are
expected for `validation-error`, not evidence of a successful creation. No other
capture error is expected. To repeat dark captures, use a scenario copy with
`colorScheme: "dark"`, preserving the process cwd paths.
## Implementer-owned visual review
- Baseline commit: `e939cd4e4b1f6b63b81411fd7766062f2d69ad0d`.
- Before: `.svelte-kit/t717/visual/before-final-light` and `before-dark`.
These use an isolated build under `.svelte-kit/t717/baseline-source`, with the
changed production form, catalog API, model, and CSS restored from baseline
Git source. The original pre-edit light capture is also retained as
`.svelte-kit/t717/visual/before-valid`.
- After: `.svelte-kit/t717/visual/final-light`, `final-dark`,
`final-interactions-light`, and `final-interactions-dark`.
- Comparisons: `.svelte-kit/t717/visual/final-comparison-light` and
`final-comparison-dark`.
- Personas: synthetic owner and non-owner permission projections; catalog
creation/reopening uses the same synthetic account.
- Viewports: 1440, 768, 390px; additional browser screenshots/checks at 320px.
- Themes: light and dark.
- States: zero repositories, empty Home/Sidebar, representative member work
records, long catalog names, unchecked/checked optional repository form,
populated inputs, and intentional Backend validation failure.
- Reviewed by the implementer using `ViewImage`: before/after contact sheets,
individual narrow/mobile populated-form screenshots, and the final mobile
dark validation-error screenshot. Reviewed context bundles and accessibility
snapshots for document status, control names/state, screenshot hashes,
console/page/request errors, and capture points.
- Fixed: catalog/form clipping at narrow content widths; repository field
disclosure/required-state handling. Chromium tests also found and fixed the
existing repository-key HTML pattern's invalid modern-regexp character class.
- Result: pass. All baseline and final main captures have document status 200
and no retained browser/UI errors. Only the intentional HTTP400 interaction
errors remain. Home, member Sidebar, and Worker launch comparisons show zero
changed pixels; catalog changes are confined to the intended surface.
## Validation and limitations
- `deno task check`: 0 errors, 0 warnings.
- Targeted model/catalog Deno tests: 18 passed.
- `deno task test:component`: 29 files, 268 tests passed.
- `deno task test:browser:empty-workspace`: passed (8 theme/width combinations).
- `deno task build`: passed.
- Web-scoped `git diff --check HEAD -- .`: passed.
- `deno task test`: 522 passed, 1 pre-existing failure in
`src/lib/workspace/console/worker-console.ui.test.ts`,
“workspace Tickets surface provides Kanban and lifecycle controls”. It fails
the unchanged Ticket detail source assertion at line 429. The same failure
was reproduced against the isolated baseline source. Evidence:
`.svelte-kit/t717/unit.log` and `baseline-ticket-failure.log`.
- Canonical OpenAPI and generated TypeScript were regenerated together.
The Web parser uses the generated nullable creation-response type directly.
Backend persistence/idempotency is covered separately by Store/catalog and
real HTTP boundary tests in `yoi-workspace-server`.
実Workspace、account、Repository、Runtime、Workerは作成しない。拒否fixtureの診断を正常系の成功として扱わず、captureの終了状態だけで視覚面を承認しない。横断検証規則は [Visual Review](../../../../docs/development/ui-ux/visual-review.md) に従う。
@@ -10,12 +10,6 @@ Deno.test("Bevel draws a plain selectable border around semantic children", asyn
const appCss = await Deno.readTextFile(
new URL("../src/app.css", import.meta.url),
);
const designLanguage = await Deno.readTextFile(
new URL(
"../../../docs/development/ui-ux/design-language.md",
import.meta.url,
),
);
for (
const contract of [
@@ -73,14 +67,6 @@ Deno.test("Bevel draws a plain selectable border around semantic children", asyn
source.includes("button, input, select, textarea"),
"Bevel must not own surface color and must keep semantic controls as children",
);
assert(
designLanguage.includes("1pxの単色borderを描くvisual wrapper") &&
designLanguage.includes(
"照明、raised/inset、ridge/grooveを表現しない",
) &&
designLanguage.includes("text/content areaへ適用する"),
"The design language must define Bevel as a plain border without surface ownership",
);
});
Deno.test("Workspace showroom exercises closed and adjacent borders", async () => {
@@ -83,12 +83,6 @@ Deno.test("Shell regions use selected Bevel edges while open separators use Beve
import.meta.url,
),
);
const designLanguage = await Deno.readTextFile(
new URL(
"../../../docs/development/ui-ux/design-language.md",
import.meta.url,
),
);
assert(
rootLayout.includes('class="app-shell__topbar-bevel"') &&
@@ -109,18 +103,9 @@ Deno.test("Shell regions use selected Bevel edges while open separators use Beve
"Desktop shell boundaries must use one selected border edge and Mobile must share Header fold state",
);
assert(
designLanguage.includes(
"Headerのbottom edgeとSidebarのright edgeだけを有効",
) &&
designLanguage.includes("Mobileのfold controlはHeaderに置く") &&
designLanguage.includes("main contentと同時表示しない") &&
designLanguage.includes("同じlayerではheading、本文、Lineの端を揃え") &&
designLanguage.includes(
"親layoutがそのlayer全体へinline方向の余白を与え",
) &&
showroomCss.includes(".resource-list {") &&
showroomCss.includes(".resource-list {") &&
showroomCss.includes("margin-inline: var(--space-2)"),
"The design language and showroom must preserve adjacent area and line hierarchy",
"showroomはresource layer全体の余白を維持する",
);
assert(
sidebarCss.includes(".section-action {") &&
@@ -51,12 +51,6 @@ Deno.test("Workspace typography tokens bind the documented three-level scale", a
const appCss = await Deno.readTextFile(
new URL("../src/app.css", import.meta.url),
);
const designLanguage = await Deno.readTextFile(
new URL(
"../../../docs/development/ui-ux/design-language.md",
import.meta.url,
),
);
for (
const contract of [
@@ -73,12 +67,4 @@ Deno.test("Workspace typography tokens bind the documented three-level scale", a
) {
assert(appCss.includes(contract), `app.css must preserve ${contract}`);
}
assert(
designLanguage.includes("--font-size-title /* 24px */") &&
designLanguage.includes("--font-size-body /* 14px */") &&
designLanguage.includes("--font-size-compact /* 12px */") &&
designLanguage.includes("`12px`未満と`13px`を使わない"),
"The design language must preserve the title, body, and compact typography contract",
);
});