Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/actions/setup-lint-toolchain/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ inputs:
sc-lint-version:
description: Released sc-lint version to install
required: false
default: "0.4.0"
default: "0.5.0"
cargo-deny-version:
description: Pinned cargo-deny version
required: false
Expand Down
21 changes: 15 additions & 6 deletions .github/actions/setup-sc-lint/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ inputs:
version:
description: Released sc-lint version to install (deliberate ecosystem pin)
required: false
default: "0.4.0"
default: "0.5.0"
repository:
description: GitHub repository slug hosting sc-lint releases
required: false
Expand Down Expand Up @@ -93,10 +93,13 @@ runs:
run: |
set -euo pipefail
version_json="$(sc-lint version --json)"
# 0.5.0+ reports data.version; 0.4.x reported data.crate_version.
actual="$(jq -r '.data.version // .data.crate_version // empty' <<<"${version_json}")"
jq -e --arg expected "${SC_LINT_VERSION}" \
'.ok == true and .data.crate_version == $expected' \
'.ok == true and ((.data.version // .data.crate_version) == $expected)' \
<<<"${version_json}" >/dev/null || {
echo "sc-lint setup: version contract failed; expected ${SC_LINT_VERSION}" >&2
echo "sc-lint setup: version contract failed; expected ${SC_LINT_VERSION}, got ${actual:-<missing>}" >&2
echo "${version_json}" >&2
exit 1
}
- name: Verify sc-lint version contract (Windows)
Expand All @@ -106,9 +109,15 @@ runs:
SC_LINT_VERSION: ${{ inputs.version }}
SC_LINT_REPOSITORY: ${{ inputs.repository }}
run: |
$value = sc-lint version --json | ConvertFrom-Json
if (-not $value.ok -or $value.data.crate_version -ne $env:SC_LINT_VERSION) {
throw "sc-lint setup: expected version $env:SC_LINT_VERSION, got $($value.data.crate_version)"
$raw = sc-lint version --json
$value = $raw | ConvertFrom-Json
$actual = if ($null -ne $value.data.version -and "$($value.data.version)" -ne '') {
$value.data.version
} else {
$value.data.crate_version
}
if (-not $value.ok -or $actual -ne $env:SC_LINT_VERSION) {
throw "sc-lint setup: expected version $env:SC_LINT_VERSION, got $actual. $raw"
}
- name: Materialize pinned sc-lint Python utilities (Unix)
if: runner.os != 'Windows'
Expand Down
15 changes: 12 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ jobs:
- name: cargo clippy
run: cargo clippy --workspace -- -D warnings

- name: Install sc-lint from crates.io
run: cargo install sc-lint --version 0.4.0 --locked
- name: Set up sc-lint (published release bundle)
uses: ./.github/actions/setup-sc-lint

- name: sc-lint check
run: sc-lint check native --config .sc-lint.toml
Expand Down Expand Up @@ -290,9 +290,18 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Enforce boundaries/*.toml against Cargo.toml

- name: Set up sc-lint (published release bundle)
uses: ./.github/actions/setup-sc-lint

- name: sc-lint boundary inventory
run: sc-lint lint sc-boundary --config .sc-lint.toml

- name: Enforce io_forbidden grep policy
run: python3 scripts/check-boundaries.py

- name: Verify ui/ matches crates/wyvern/ui/
run: bash scripts/check-ui-sync.sh

- name: Verify share/ and scripts/ext match crates/wyvern/
run: bash scripts/check-share-sync.sh
8 changes: 6 additions & 2 deletions .sc-lint.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# sc-lint workspace config (Phase A — a.7)
# Install: cargo install sc-lint --version 0.4.0 --locked
# sc-lint workspace config (Phase A — a.7, upgraded 0.5.0)
# Local install: cargo install sc-lint --version 0.5.0 --locked
# CI install: .github/actions/setup-sc-lint (GitHub release bundle)
# Canonical check: sc-lint check native --config .sc-lint.toml

[tool.sc-lint]
minimum_version = "0.5.0"

[workspace]
root = "."
3 changes: 3 additions & 0 deletions boundaries/planning.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[planning]
# Wyvern does not use inventory-parity sprint escalation yet; set a stable sentinel.
current_sprint = "J.5"
37 changes: 33 additions & 4 deletions boundaries/wyvern/cli.toml → boundaries/wyvern-cli/cli.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
boundary_id = "BOUNDARY-WyvernCli"
owner_package = "wyvern-cli"
owner_crate_path = "wyvern_cli"
name = "WyvernCli"

[public]
facade = "run_from_loaded"

[implementation]
type = "PipelineError"
module = "wyvern_cli"
visibility = "public"
constructor = "none"

[composition]
roots = [
"CliArgs",
"PipelineError",
"run_from_loaded",
"spawn_embedded_viewer",
"run_wizard_command",
"ExtensionRegistry",
"load_command_input",
]

[dependencies]
# wyvern-viewer: optional dep for dev binary-path helpers; embedded spawn uses subprocess (no wry in CLI)
allowed_dependents = []
allowed_dependencies = [
"wyvern-schema",
Expand All @@ -22,15 +42,24 @@ allowed_dependencies = [
"libc",
]
forbidden_edges = [

{ from = "wyvern-cli", to = "wyvern-mcp" },
{ from = "wyvern-cli", to = "wry" },
{ from = "wyvern-cli", to = "winit" },
{ from = "wyvern-cli", to = "rfd" },
]

[ownership]
io_owns = ["stdin_reading", "stdout_writing", "stderr_writing", "arg_parsing", "host_options", "viewer_flag", "embedded_viewer_spawn", "viewer_show_hide", "workflow_script_spawn", "wizard_chain_loop"]
io_forbidden = ["http_server", "webview_creation", "static_file_serve", "dialog_content_html"]
[references]
scope = "outside_owner_crate"
forbidden = []

[testing]
allowed_test_double_paths = []
forbidden_test_bypasses = []

[enforcement]
lint_rules = ["LINT-BOUNDARY-CLI-NO-WINDOW-DIRECT"]
review_gates = ["no_direct_webview_deps"]

[status]
state = "concrete_landed"
54 changes: 50 additions & 4 deletions boundaries/wyvern-host/host.toml
Original file line number Diff line number Diff line change
@@ -1,19 +1,65 @@
boundary_id = "BOUNDARY-WyvernHost"
owner_package = "wyvern-host"
owner_crate_path = "wyvern_host"
name = "WyvernHost"

[public]
facade = "run"

[implementation]
type = "HostError"
module = "wyvern_host"
visibility = "public"
constructor = "none"

[composition]
roots = [
"run",
"begin",
"DialogHandle",
"HostOptions",
"HostError",
"ViewerMode",
"BrowserRegistryEntry",
]

[dependencies]
allowed_dependencies = ["wyvern-schema", "serde", "serde_json", "axum", "tokio", "tower", "tower-http", "tracing", "rfd", "webbrowser", "dirs", "pulldown-cmark", "ammonia", "wyvern-wizard"]
allowed_dependents = ["wyvern-cli", "wyvern-mcp"]
allowed_dependencies = [
"wyvern-schema",
"serde",
"serde_json",
"axum",
"tokio",
"tower",
"tower-http",
"tracing",
"rfd",
"webbrowser",
"dirs",
"pulldown-cmark",
"ammonia",
"wyvern-wizard",
]
forbidden_edges = [

{ from = "wyvern-host", to = "wyvern-cli" },
{ from = "wyvern-host", to = "wyvern-mcp" },
{ from = "wyvern-host", to = "wry" },
{ from = "wyvern-host", to = "winit" },
]

[ownership]
io_owns = ["tcp_bind", "http_server", "static_file_serve", "dialog_session", "wizard_session", "wizard_routes", "report_routes", "report_session", "result_channel", "native_file_picker", "browser_registry", "system_browser_launch", "dialog_content_html", "dialog_preview_html"]
io_forbidden = ["stdin_reading", "stdout_writing", "arg_parsing", "webview_creation", "inline_html_embed", "html_template_generation", "mcp_protocol", "embedded_viewer_spawn", "wizard_history_internals", "wizard_domain_logic", "workflow_script_spawn", "wizard_chain_loop"]
[references]
scope = "outside_owner_crate"
forbidden = []

[testing]
allowed_test_double_paths = []
forbidden_test_bypasses = []

[enforcement]
lint_rules = ["LINT-BOUNDARY-HOST-NO-CLI", "LINT-BOUNDARY-HOST-NO-WEBVIEW"]
review_gates = ["http_host_only"]

[status]
state = "concrete_landed"
30 changes: 26 additions & 4 deletions boundaries/wyvern-mcp/mcp.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,39 @@
boundary_id = "BOUNDARY-WyvernMcp"
owner_package = "wyvern-mcp"
owner_crate_path = "wyvern_mcp"
name = "WyvernMcp"

[public]
facade = "wyvern_mcp"

[implementation]
visibility = "trait_only"

[composition]
roots = []

[dependencies]
allowed_dependencies = ["wyvern-schema", "wyvern-host", "tokio"]
allowed_dependents = []
allowed_dependencies = ["wyvern-schema"]
forbidden_edges = [

{ from = "wyvern-mcp", to = "wyvern-cli" },
{ from = "wyvern-mcp", to = "wyvern-wizard" },
{ from = "wyvern-mcp", to = "wry" },
{ from = "wyvern-mcp", to = "winit" },
]

[ownership]
io_owns = ["mcp_stdio_transport", "tool_registration", "persistent_host_lifecycle"]
io_forbidden = ["arg_parsing", "stdin_readline_loop", "direct_wizard_navigation", "http_server_impl"]
[references]
scope = "outside_owner_crate"
forbidden = []

[testing]
allowed_test_double_paths = []
forbidden_test_bypasses = []

[enforcement]
lint_rules = ["LINT-BOUNDARY-MCP-NO-CLI", "LINT-BOUNDARY-MCP-WINDOW-VIA-API-ONLY"]
review_gates = ["phase_e_stub"]

[status]
state = "planned"
38 changes: 35 additions & 3 deletions boundaries/wyvern-schema/schema.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,34 @@
boundary_id = "BOUNDARY-WyvernSchema"
owner_package = "wyvern-schema"
owner_crate_path = "wyvern_schema"
name = "WyvernSchema"

[public]
facade = "Command"

[implementation]
type = "Command"
module = "wyvern_schema"
visibility = "public"
constructor = "none"

[composition]
roots = [
"ButtonLabel",
"ChromeStatus",
"ChromeTitle",
"Command",
"ValidationError",
"ErrorCode",
"CommandResult",
"validate",
]

[dependencies]
allowed_dependents = ["wyvern-cli", "wyvern-host", "wyvern-wizard", "wyvern-mcp"]
allowed_dependencies = ["serde", "serde_json", "strsim"]
forbidden_edges = [

{ from = "wyvern-schema", to = "wyvern-cli" },
{ from = "wyvern-schema", to = "wyvern-wizard" },
{ from = "wyvern-schema", to = "wyvern-mcp" },
Expand All @@ -13,9 +37,17 @@ forbidden_edges = [
{ from = "wyvern-schema", to = "rfd" },
]

[ownership]
io_owns = ["type_definitions", "validation_logic", "error_message_formatting"]
io_forbidden = ["file_io", "network_io", "window_creation", "webview", "async_runtime"]
[references]
scope = "outside_owner_crate"
forbidden = []

[testing]
allowed_test_double_paths = []
forbidden_test_bypasses = []

[enforcement]
lint_rules = ["LINT-BOUNDARY-SCHEMA-PURE-LOGIC"]
review_gates = ["pure_logic_only"]

[status]
state = "concrete_landed"
38 changes: 33 additions & 5 deletions boundaries/wyvern-viewer/viewer.toml
Original file line number Diff line number Diff line change
@@ -1,20 +1,48 @@
boundary_id = "BOUNDARY-WyvernViewer"
owner_package = "wyvern-viewer"
owner_crate_path = "wyvern_viewer"
name = "WyvernViewer"
status = "active"

[public]
facade = "DismissError"

[implementation]
type = "DismissError"
module = "wyvern_viewer"
visibility = "public"
constructor = "none"

[composition]
roots = [
"DismissError",
"ViewportBounds",
"resolve_bootstrap_size",
"post_dismissed",
"is_wizard_dialog_url",
]

[dependencies]
allowed_dependents = ["wyvern-cli"]
allowed_dependencies = ["wry", "winit", "url", "tracing", "serde", "serde_json", "gtk"]
forbidden_edges = [
{ from = "wyvern-viewer", to = "wyvern" },

{ from = "wyvern-viewer", to = "wyvern-cli" },
{ from = "wyvern-viewer", to = "wyvern-mcp" },
{ from = "wyvern-viewer", to = "wyvern-host" },
{ from = "wyvern-viewer", to = "wyvern-schema" },
]

[ownership]
io_owns = ["webview_open_url", "webview_show_hide", "viewer_lifecycle_stdin", "chrome_presentation_ipc"]
io_forbidden = ["http_server", "stdout_writing", "inline_html"]
[references]
scope = "outside_owner_crate"
forbidden = []

[testing]
allowed_test_double_paths = []
forbidden_test_bypasses = []

[enforcement]
lint_rules = ["LINT-BOUNDARY-VIEWER-URL-ONLY"]
review_gates = ["url_only_webview"]

[status]
state = "concrete_landed"
Loading
Loading