Skip to content
Merged
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
13 changes: 13 additions & 0 deletions scripts/ci/check-scopes.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@
"NOTICE"
],
"rules": [
{
"paths": [
"docs/internals/architecture/appserver/app-protocol-*.schema.json"
],
"checks": [
"gui",
"architecture",
"coding",
"apphost",
"appservice"
],
"reason": "App Protocol shared contract and direct consumers"
},
{
"paths": ["gui/**", "scripts/gui/**"],
"checks": ["gui"],
Expand Down
13 changes: 13 additions & 0 deletions tests/appserver/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
SessionEventKindV1,
SessionEventV1,
SessionIdentityV1,
SessionModelSelectV1,
SessionModelsV1,
SessionOpenSpecV1,
SessionScopeV1,
SessionSnapshotRequestV1,
Expand Down Expand Up @@ -150,6 +152,7 @@ async def scenario() -> None:
mux = MuxSpaceV1("mux", "dev", 1, ())
snapshot = SessionSnapshotV1(identity, "Coding", 0, 0, False)
attachment = MuxAttachmentV1("a", mux, 1, ())
models = SessionModelsV1(None, ())
event = AttachmentEventV1(
"a", "m", SessionEventV1("s", 1, SessionEventKindV1.TURN_COMPLETED)
)
Expand All @@ -172,6 +175,16 @@ async def scenario() -> None:
),
("close_member", MuxMemberCloseV1(selector, "m"), mux),
("snapshot_session", SessionSnapshotRequestV1("a", 1, "m"), snapshot),
(
"list_session_models",
SessionSnapshotRequestV1("a", 1, "m"),
models,
),
(
"select_session_model",
SessionModelSelectV1("a", 1, "m", "provider:model"),
models,
),
("start_turn", TurnTextV1("a", 1, "m", "start"), AckV1()),
("steer_turn", TurnTextV1("a", 1, "m", "steer"), AckV1()),
("follow_up_turn", TurnTextV1("a", 1, "m", "follow up"), AckV1()),
Expand Down
10 changes: 6 additions & 4 deletions tests/architecture/test_hosted_application_g11.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,11 +245,13 @@ def test_g11_package_budgets_keep_new_owners_reviewable() -> None:
# 271 lines to this exact group; all protocol modules still count.
# See hosted-session-workflow-g17.md, Reviewability Budget Supplement.
"appserver": 2_100,
"appservice-core": 1_500,
# Attachment-scoped model discovery and selection extend the existing
# AppService authority boundary without exposing provider credentials.
"appservice-core": 1_550,
"appservice-continuity": 1_250,
# Optional execution adds omission metadata and a synchronous projection
# seam; its two owners have a separate budget in the Wave A contract.
"coding-adapter": 420,
# Optional execution plus the redacted, session-local model control
# bridge remain isolated in the Coding AppService adapter.
"coding-adapter": 470,
"harnesstui-mux": 600,
}
for name, paths in groups.items():
Expand Down
36 changes: 36 additions & 0 deletions tests/ci/test_change_gates.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,42 @@ def load_script(name: str):


class ScopeTests(unittest.TestCase):
def test_app_protocol_schema_selects_only_direct_consumers(self):
path = "docs/internals/architecture/appserver/app-protocol-v1.schema.json"
actual = self.selected(path)

self.assertEqual(
actual,
{
"docs",
"gui",
"architecture",
"coding",
"apphost",
"appservice",
"host_runtime",
},
)
self.assertFalse(
{
"ai",
"agent",
"harness",
"harness_native",
"harnesstui",
"coding_ui",
"tui_unit",
"tui_playback",
"tui_native",
"hosting",
"windows_shell",
"install",
"lsp",
"foundation",
}
& actual
)

def test_gui_code_and_tooling_select_only_gui_and_docs(self):
for path in ("gui/src/App.tsx", "gui/src-tauri/Cargo.lock", "gui/pnpm-lock.yaml", "scripts/gui/run.mjs"):
with self.subTest(path=path):
Expand Down
Loading