277 Commits
Author SHA1 Message Date
Qiu Yuzhou 9788ffe484 feat(rules): fix custom rule actions to their scheme 2026-10-30 20:40:20 +08:00
Qiu Yuzhou 3e64743237 fix(runtime): allow initial balancer startup
Initial multi-server checks can consume the entire five-second listener
budget before sslocal binds its inbound ports. Allow 15 seconds for
listeners and 30 seconds for GUI startup health confirmation.

Include endpoint readiness diagnostics and a delayed-start regression.
2026-10-30 08:52:36 +08:00
Qiu Yuzhou b1b9fcfd37 fix(sip008): emit UUID identifiers in lowercase 2026-10-28 18:28:58 +08:00
Qiu Yuzhou 9ccee1fc53 refactor(servers): simplify latency details 2026-10-27 01:19:35 +08:00
Qiu Yuzhou 923f004527 feat: add third-party components and licenses window 2026-10-26 19:53:38 +08:00
Qiu Yuzhou 35c74d40c5 feat: bundle offline dependency provenance and license metadata 2026-10-26 19:06:38 +08:00
Qiu Yuzhou 47206c9d4c test(plugin): verify argument behavior across overrides and activation 2026-10-26 01:21:04 +08:00
Qiu Yuzhou a01be54971 fix: preserve weak release check without mutable local 2026-10-25 23:15:40 +08:00
Qiu Yuzhou cb771e67ba fix(subscription): namespace SIP008 custom date fields 2026-10-25 22:55:45 +08:00
Qiu Yuzhou 3a10b7524c refactor: consolidate subscription update execution ownership 2026-10-25 22:30:19 +08:00
Qiu Yuzhou f3ba330cf4 refactor: centralize subscription automatic update transitions 2026-10-25 22:06:39 +08:00
Qiu Yuzhou 34caebf322 feat: add GUI-scoped subscription automatic updates (#1516)
* feat: add GUI-scoped subscription automatic updates

* fix: drain newly due subscription updates during a batch

* style: use segmented subscription update pickers
2026-10-25 20:21:06 +08:00
Qiu Yuzhou 2241d3f7f9 fix(window): stop policy bouncing during launch activation
Keep regular policy while windows remain open to avoid repeated Dock registration. Share the activation retry budget across visibility events and stop permanently after exhaustion.
2026-10-25 17:50:18 +08:00
Qiu Yuzhou 59ce386bad test(rules): strengthen isolation and remove redundant checks 2026-10-25 14:32:12 +08:00
Qiu Yuzhou 86909bee13 refactor(rules): centralize document commits 2026-10-25 14:32:12 +08:00
Qiu Yuzhou 06e9fddb59 test(rules): align fixtures with preset ownership
Select presets explicitly so document stores, runtime preparation,
and browsing assertions use the intended rule sources.
2026-10-25 14:32:12 +08:00
Qiu Yuzhou 32709333f5 refactor(rules): require explicit preset selection
Remove lossy default-action writes that can replace china-proxy
with gfwlist. Preserve legacy preference reads and derive the
default action from the selected preset.

Update tests to use explicit presets and verify identity,
legacy compatibility, and no-op reselection.
2026-10-25 14:32:12 +08:00
Qiu Yuzhou 168ff2e93e feat(rules): reorder presets and default to GFWList 2026-10-25 14:32:12 +08:00
Qiu Yuzhou f6abd4343e feat(rules)!: add isolated routing presets
Add Mainland China proxy routing with independent rule workspaces.
Preserve existing routing choices through equivalent preset mappings.

BREAKING CHANGE: existing custom rules and enablement settings are
not migrated. Recreate them in the appropriate preset.
2026-10-25 14:32:12 +08:00
Qiu Yuzhou e3d38718c0 test: make HTTP and plugin checks deterministic 2026-10-24 14:16:34 +08:00
Qiu Yuzhou aaa16ebf9f test(http): shorten first-byte timeout check 2026-10-24 03:35:29 +08:00
Qiu Yuzhou 5d6b8f433f test: move process lifecycle checks to smoke 2026-10-24 03:27:28 +08:00
Qiu Yuzhou 1003b904dc test(doh): remove CI timing assumptions
CI scheduling can exhaust the fallback budget or exceed the elapsed-time
assertion. Separate record filtering and control deadline delivery so
tests verify fallback and request cancellation directly.
2026-10-24 03:14:03 +08:00
Qiu Yuzhou b7648ceecd test(smoke): stop on missing deployment receipt 2026-10-24 02:51:39 +08:00
Qiu Yuzhou ca9215099b fix(tests): restore strict test compilation 2026-10-24 02:51:27 +08:00
Qiu Yuzhou 366bb43711 test(agent): replace timed reload integration test 2026-10-24 02:51:15 +08:00
Qiu Yuzhou c708cd8d19 feat(ui): debounce transient status rows via shared display gate
The home run-control card and the menu-bar status card render the agent
and system-proxy status rows straight from snapshot replacements, so fast
operations (e.g. proxy mode switches) flash transient states like
"applying" before settling.

Add a presentation-layer debounce shared by both surfaces:

- TransientDelayGate: per-stream gate where stable values display
  immediately, transient values (starting/applying/repairing) display
  after 400 ms and are dropped when superseded, and displayed transients
  are held for at least 400 ms.
- StatusDisplayModel: app-level shared model deriving agent and
  system-proxy payloads (row + detail + hint) from workflow snapshots
  through two independent gates; domain facts keep their cadence.
- Wire the model through the composition root into RuntimeControlCard
  and StatusCardView; toggles, approval actions, the difference view and
  target/mode rows keep reading the raw snapshot.
2026-10-24 02:22:39 +08:00
Qiu Yuzhou 2fdcb5ab93 refactor(test): drop source-scanning openWindow guard 2026-10-24 00:50:07 +08:00
Qiu Yuzhou 1262d17d61 feat(agent): omit sslocal log timestamps 2026-10-24 00:13:58 +08:00
Qiu Yuzhou 4845cbf673 fix(logging): detect upstream levels case-insensitively 2026-10-23 23:54:54 +08:00
Qiu Yuzhou d3faf610c1 feat(diagnostics): add selectable log table 2026-10-23 19:25:33 +08:00
Qiu Yuzhou 69a1257430 fix: resolve non-deprecation unit test build warnings 2026-10-23 05:32:38 +08:00
Qiu Yuzhou d48a21b2c8 fix(agent): extend listener readiness deadline 2026-10-23 05:15:17 +08:00
Qiu Yuzhou 09e4d2e097 fix(tests): avoid blocking async test workers 2026-10-23 03:46:19 +08:00
Qiu Yuzhou 17848b6fde ci: add NG2 validation workflow and format checks 2026-10-23 03:05:14 +08:00
Qiu Yuzhou 3baee572ac fix: restore compilation after file extraction 2026-10-23 02:50:13 +08:00
Qiu Yuzhou b6b9349d64 style: resolve SwiftLint violations 2026-10-23 01:10:40 +08:00
Qiu Yuzhou 17c9f15928 fix(window): bring presented window reliably to front at launch
Keyboard-launcher launches (Raycast/Spotlight Enter) left the
LSUIElement app unforegrounded with a missing Dock icon until Mission
Control forced a refresh. Investigation across real-machine rounds
(recorded in the ADR-0017 supplements) pinned three cooperating causes:

- The launch activation retry never started at launch: the workspace
  window's participation events (anchor attach / occlusion / key) could
  all miss the launch moment when content installed before the window
  became visible and the visibility notification fired before the
  anchor attached. A deferred visibility rescan plus re-armable chain
  (until truly settled) close this gap.
- NSApp.isActive can report an activation illusion while the menu bar
  still belongs to the previous frontmost app, so the settle check now
  requires both isActive and menu bar ownership.
- A same-turn accessory->regular bounce is coalesced away by the
  system; forced activation is a three-hop sequence with real settle
  delays (accessory -> 0.1s -> regular -> 0.15s -> activate), which
  re-registers the app with WindowServer/Dock and reclaims the menu
  bar. Each acting attempt also re-asserts makeKeyAndOrderFront and
  orderFrontRegardless as a visible-layer fallback.

Diagnostics: launchActivationRetry and windowAnchorAttached events
(unified-log category "window") record per-attempt facts (activation,
local policy, frontmost app, menu bar owner, space, window visibility);
user-environment facts stay out of shared diagnostic reports.
2026-10-22 03:24:14 +08:00
Qiu Yuzhou f847c01e70 chore(deps): update v2ray-plugin to v1.4.0 2026-10-22 00:49:56 +08:00
Qiu Yuzhou 7a01167719 test: clean up Keychain test identities 2026-10-21 19:34:18 +08:00
Qiu Yuzhou f9e95474e5 refactor: adopt age configuration storage
Replace the custom encrypted container with AgeSwift 0.1.0 so standard
age tools can inspect sensitive configuration independently of the app.

Use independent Keychain X25519 identities for catalog.age and
proxy-listening.age. Preserve atomic commits and confirmed recovery;
reject historical NG2 formats without migration or cleanup.
2026-10-21 14:31:32 +08:00
Qiu YuzhouandDeepSeek Harness 7977daafea refactor: keep test doubles and test-only wrappers out of production
Move InMemoryDiagnosticReportExporter and InMemoryConfigurationGroupFileExporter
from App/PlatformEffects to Tests/Support: both are test doubles with no
production caller, and production composition wires only the AppKit adapters.

Delete RuleRuntimeCompiler.validation, a wrapper whose only callers were two
assertion blocks in the controller deployment test; those restated
custom-to-custom shadowing and validation order-independence, both pinned by
CustomRuleValidatorTests and RuleAnalysisTests. RuleRuntimeCompiler.compile
stays and keeps its production caller.

Co-Authored-By: DeepSeek Harness <noreply@deepseek.com>
2026-10-21 02:44:35 +08:00
Qiu YuzhouandDeepSeek Harness 5872015ca0 test: drop dead scaffolding assertions
Six sites re-asserted the predicate waitUntilRuntimeSettles already checks,
with no suspension point in between, so they could never fail; their intent
messages are folded into comments where one was not already stated.

Two commit-failure cases asserted the fake's bookkeeping (updateCalls stays
empty) which the fake guarantees by throwing before recording; the outcome
and committed-snapshot assertions already prove the real behavior.

Also drop a no-op loop that mutated a discarded struct copy, a duplicated
isWellFormed line, two WorkspaceRoute cases subsumed by the constructor and
the publish-count case, a duplicated presentation-message assertion, and the
round-trip halves of two payload-shape cases already covered case-by-case.

Co-Authored-By: DeepSeek Harness <noreply@deepseek.com>
2026-10-21 02:23:28 +08:00
Qiu YuzhouandDeepSeek Harness 78bafea90f test: drop assertions that restate the language or a fixture
Each removed assertion holds by construction and can never fail:

- jsonData() compared with itself cannot detect cross-run byte stability;
  bindAddress and mode are literal-returning computed properties
- RuleAction/RuleSourceKind allCases assertions pin synthesized enum order
  (neither allCases list is used in production); the persisted action tokens
  stay pinned by the kept rawValue assertions and source-kind tokens by
  fixture decoding through RuleSnapshotStore
- memberwise-constructor echo in RuleSourceIdentity, fixture-guaranteed
  name == id rows, a share draft field pair built from one string, and a
  local struct compared to its own assignment
- the synthesized-Codable round trip through literal JSONEncoder/JSONDecoder

The duplicate-import assertion becomes a real check: Set of node ids instead
of a count that restated roots.count, which is what its comment claims.

Co-Authored-By: DeepSeek Harness <noreply@deepseek.com>
2026-10-21 02:04:21 +08:00
Qiu YuzhouandDeepSeek Harness e7116a5ebd test: merge duplicated cases into the stronger one
Every case here restates a rule another test already pins with the same or a
wider input class:

- the activation group case is byte-identical to its neighbour, minus an extra
  assertion; the rule snapshot version guard is re-driven with a second value
  of the same schemaVersion check; the global-mode deployment-failure case is
  a mode-literal copy of the strictly stronger direct-mode one; the clear-
  failure case duplicates the deferred-retry sibling
- two RuntimeDocument projection cases only re-map locals, already asserted as
  full array equality; the IPv6-LAN endpoint case repeats the direct-mode case
  (the derivation reads only ports)
- the three HTTP export cases varied only listenerMode while the derivation
  ignores it and one name contradicted its own expectation; one loop over all
  listener modes now states the real rule
- the 0700/0600 permission baseline is one AtomicFileWriter behavior and stays
  pinned through RuntimeFileStoreTests, which also covers self-heal and atomic
  replace

The command-boundary case keeps its mixed-scenario isolation check (four
commands, four independent adapter counters) and drops only its unfalsifiable
queriedTargetIDs claim.

Co-Authored-By: DeepSeek Harness <noreply@deepseek.com>
2026-10-21 01:46:29 +08:00
Qiu YuzhouandDeepSeek Harness d63d04c114 test: drop matrix and ACL cases whose inputs never reach the unit
testExternalSettingsChangesNeverSupplyAFallbackOrAlterThreeStateResults
mutates a preferences fixture 12 ways but never passes it to RulesWorkflow
(which takes no preferences) and the matcher path is a pure function of the
collection; the 48 assertions are four matcher outcomes repeated 12 times and
each outcome is covered elsewhere.

The two ACL "does not load custom rules" cases build a customRules array that
ProxyACLDocument.global/direct cannot receive (both take only a URL), so their
contains() negatives could never fail; the template shapes are pinned by
ProxyACLTests and the behavioral claim by CustomRuleControllerTests.

Co-Authored-By: DeepSeek Harness <noreply@deepseek.com>
2026-10-21 01:19:15 +08:00
Qiu YuzhouandDeepSeek Harness 28c6e82555 test: drop cases whose injected failure can never fire
Four listening-file failure cases inject InMemoryProxyListeningStore.saveError
and assert saved == nil, which the fixture guarantees because save throws
before assigning; the only production save call is updateListening and none of
these paths reaches it. Their behavioral content is covered by sibling tests,
so keep only the three assertions that were unique there (agent intent
persistence, runtime stopped after the off cascade, no commit in flight) and
move them into those siblings.

Same pattern in testProxyExceptionsIgnoreListeningPersistenceFailure: the
path calls only the non-throwing updateProxyExceptions, so its updateError
injection is inert and the rest duplicates the sibling case. The plugin
diagnostic test fed an unproducible fixture (user-sourced facts never carry a
version, since managedInfo exists only for managed sources); assert the
reachable property, the source label in the report row. FakeSettingsSaveError
and the now-unused saveError seam go with them.

Co-Authored-By: DeepSeek Harness <noreply@deepseek.com>
2026-10-21 01:09:28 +08:00
Qiu YuzhouandDeepSeek Harness 26ecc5a11e test: drop assertions that cannot fail and the doubles they exercised
Three tests claimed coverage they could not deliver:

- subscription URL credential cleanup asserted a lookup derived from the
  already-empty subscription list, so it held even on a leak; production has
  no separate URL credential store (SubscriptionRecord.url is a plain field)
- the runtime log event sweep planted no secret values, so its secret half
  could never fail; keep the live JSON-dump check and rename the test to match
- clipboard and QR saver tests exercised only in-memory doubles that live in
  production source and have no other caller; delete the six tests and the
  three doubles (AppKit adapters stay untested, as before)

Co-Authored-By: DeepSeek Harness <noreply@deepseek.com>
2026-10-21 00:45:44 +08:00
Qiu Yuzhou 2c75ee67ec feat(runtime): hot reload ACL rules with signals 2026-10-20 23:54:05 +08:00
Qiu Yuzhou 8508080480 fix: observe agent deployment failures without port probes 2026-10-20 23:49:00 +08:00