Pin gaoyifan/china-operator-ip china.txt and compile its IPv4 CIDRs into
the proxy_all ACL alongside China domain candidates. Explicit maintainer
update normalizes and deduplicates CIDRs and blocks replacement on
abnormal format, corruption, scale change, or all-invalid input.
Closes#64
77 → 0 warnings. Split oversized functions and files: controller and
agent extension files, standalone RuleSet/ProxySettingsFileStore/
SslocalListenSettings/LegacyImportService, test classes into topic
extensions. Regroup activation options into RuntimeDocumentOptions and
converter metadata into Provenance.
Runtime controller DI seams widen private → internal so the extension
files stay cohesive; new controller files are registered in the
architecture guard exemption list; Agent target adds RuleSet and
SslocalListenSettings to project.yml. Test JSON literals wrap inside
the string literal only.
Introduce a source-independent rule model (action, domain/CIDR match,
source identity, conflict metadata) and ship a pinned geolocation-cn
snapshot produced by an explicit maintainer update. Rule mode with
proxy-when-unmatched compiles China domains as direct candidates into a
proxy_all ACL; the sub-option is selectable and persisted from home and
the status menu. Ordinary builds only read the local snapshot and fail
when it is missing or corrupt.
Global mode now deploys a minimal proxy_all ACL carrying only the fixed
local safety rules, so public targets default through Shadowsocks while
loopback/RFC1918/link-local/ULA/localhost/*.local/no-dot hosts stay
direct for SOCKS, HTTP, and LAN-sharing clients. System proxy exceptions
include that fixed scope; IPv6 system-exception limits are documented
with the ACL as the routing guarantee. Mode switches keep the
full-restart and rollback path.
Closes#62
The toggle only gated a convenience endpoint: system proxy never used
the HTTP port, which serves the terminal export line and LAN proxy.
Stored httpProxyEnabled:false is silently ignored, no migration.
Proxy-endpoint settings rows lose their subtitles; glossary term is
now the permanent "HTTP proxy inbound".
- window.title tracks the destination via composition-root wiring
into WorkspaceWindowOpeningAdapter.bindTitle; drop the static
"ShadowsocksX-NG 2.0" title
- delete the 28pt shell destinationHeader; subscription and
diagnostics actions move into the unified toolbar
- settings save/reset stay with the form as a top action row in
SettingsView; form-level commit actions read wrong in a toolbar
Issue #49: introduce CatalogWorkflowDependencies as the composition-only
adapter bundle and stop exposing implementation collaborators as workflow
properties. MainApp now assembles all production adapters explicitly (the
workflow creates no production defaults); tests assemble hermetic fakes via
a shared fixture in CatalogFixtures. Subscription tests swap fetch behavior
on the injected fake instead of mutating the workflow. An architecture
deletion check fails when UI source files reference implementation
collaborators or raw catalog/credential storage types, and a hermetic
assembly test proves the workflow runs entirely on injected fakes.
Issue #47: application-layer ProxyControlWorkflow wrapping the existing
ProxyRuntimeController with a whole-published ProxyControlSnapshot (typed
runtime facts, current mode, available modes, active-target facts with
safe path summary, skipped-invalid-server count, HTTP export capability)
and typed async commands (enable/disable/mode) that republish the full
snapshot on completion. Production runtime adapter delegates to the
controller without duplicating generation, health gating or system-proxy
ownership; catalog target facts arrive through a narrow seam
(CatalogTreeSnapshot.pathSummary) that never exposes the tree.
Status menu now reads runtime state and issues proxy commands only via
the workflow snapshot; catalog tree, activation and subscription actions
stay on CatalogWorkflow. MainApp wires the production adapters once as
composition root. No change to persistence order, failure taxonomy,
mode-availability policy (#46), catalog commit sync (#40), settings
(#44) or diagnostics (#43) seams.
Tests: fake-adapter snapshot/command/boundary contract tests plus
real-controller integration matrix (enable failures, approval, system
proxy, mode persistence failure and no-op) and an integration-level
status-menu model test proving the menu derives everything from the
workflow. Unavailable-mode no-op and runtime-stop-failure items of the
spec matrix are vacuous after ADR-0007 (no constructible unavailable
ProxyMode; controller stop path has no distinct failure category).
- rollback() returns CredentialRollbackOutcome and updateServer wraps
commit failures in CommitError carrying it, so tests assert through
the seam instead of poking credential store state
- hoist pluginNotManaged into form validation: form rejections stay
bare ServerFormError and never touch credentials
New UI must bind projections and send typed commands only.
Views were re-deriving delete confirm, move destinations,
activation eligibility, and drag payload from domain state.
Empty manual-group delete is no longer instant — always one confirmation.
Drop the UserDefaults intent mirror and read the toggle state only from the
system login-item registration status (approval-pending counts as enabled);
default to off until the user enables it, and stop resetting it with proxy
preferences (ADR-0005).
Add an application-layer CatalogCommitCoordinator as the single commit
entry for normal configuration changes: copy -> mutate -> atomic persist
-> publish committed state -> async runtime convergence toward the just
committed in-memory snapshot. Commits complete at persist; convergence
reports structured outcomes (converged / revalidated / failed /
clearedAndStopped) and never blocks or rolls back the commit. Each commit
bumps a generation; superseded syncs end before starting or have their
late results discarded, so only the latest snapshot can win. No automatic
retry.
CatalogRuntimeSyncing is the one new replacement seam: the production
ProxyRuntimeSyncAdapter drives the existing ProxyRuntimeController via a
snapshot-based catalogDidCommit; tests use a deterministic fake. When no
active target exists a commit no longer touches the runtime at all.
CatalogViewModel stays as a compatibility facade with unchanged published
state; the optional postCommit callback and the per-scene callback wiring
in MainApp are removed - the composition root wires the coordinator,
adapter and the (independent) Legacy import boundary exactly once.