design-15: close mutation, scope and reconciliation gaps - #20
Merged
Conversation
design-15 §6: a sidecar-declared downstream_line_uuid now joins to the downstream line's hash across the whole fleet — exact across machines and immune to NAT or shared ports — and lands in both jump_edges and the new declared_jump_edges provenance subset. Inferred (host,port) edges stay as the fallback; unknown or self references resolve to no edge.
design-15 §7 (no plugin merge): declared payload operator-target fields may now carry secret://<key>, resolved from the plugin's own encrypted vault before binding — so a saved Sub-Store endpoint can back http.operator.do without the URL re-crossing the browser. Resolution goes through plugin_host.go's new pluginSecretValue, the single non-broker read path the vault isolation test permits. Every committed vpn-core mutation (identity CRUD, bindings, rotation, applied line-user changes) re-arms a 30s debounced trigger; on fire, if the Sub-Store companion has a saved endpoint and autosync enabled, the server invokes its import as the system actor with allow/deny audits. Silent skip when disabled or inactive; no generic event bus (appendix C).
design-15 §8 server slice: applyProxyUsageSnapshot now folds on-box u_<sha256(user|line_uuid)[:16]> counter names back into (line_hash_id, proxy user id) rows before eligibility checks and monotonic diffing. The per-user total advances through the existing UserBytes path, the line granularity persists in line_user_bytes, and names that match no (bound, migrated) pair degrade to ignored — never zero-filled. Counters from users on multiple lines sum into one proxy-user total while each line keeps its own bucket, so the three-dimensional usage read model (node, line, user) lights up without a contract change.
ADR-004: the vpn-core profiles settings model gains singbox_stats_api (saved/reported/normalized with the same host:port validation as proxy_usage_xray_api), AgentLaunchConfig persists it (lattice-sdk f2a9b0e), and the generated reconfigure command exports LATTICE_SINGBOX_STATS_API.
design-15 D2: lines.sync_metadata queues a reviewed sidecar apply for one node — Plan is the metadata document itself (secret-free, so review shows the exact bytes), and the apply script re-verifies the plan hash at execution, failing closed on drift. Queueing is idempotent per (node, metadata sha). Discovery change detection queues the same sync automatically (system actor, own fingerprint map independent of the 6h audit throttle): a node's line set changing across reports queues one pending approval; unchanged or error reports queue nothing. Every byte still waits for an operator's approval.
The unified Lines view used to rebuild fleet-wide on every call — lines.get included a full rebuild plus a linear scan for a single hash. A small cache now holds the built groups and a line_hash_id index, rebuilt only after explicit invalidation: inventory ingest, proxy inbound/user/profile writes, node writes, vpn-core identity mutations, and apply outcomes. A 60s TTL is the documented safety net for a missed edge path; operator-driven mutations all invalidate explicitly, so the UI never reads stale after its own actions.
Split vpn-core and Sub-Store into canonical RBAC domains while keeping the legacy proxy grants as a one-way migration bridge. The compatibility matrix intentionally lets vpn-core front the existing native proxy API, but prevents Sub-Store from inheriting that authority. Constraint: Existing proxy:read/admin assignments must continue to authorize migrated first-party manifests Rejected: Treat substore scopes as proxy aliases | would let a publisher-only companion reach native proxy APIs Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep the asymmetric compatibility matrix until legacy proxy assignments have an explicit migration path Tested: go test ./...; go vet ./...; git diff --check
Runtime compatibility must not become authority to mint scopes in another plugin domain. Separate assignment containment from request authorization so legacy proxy grants can migrate forward while canonical vpn-core and Sub-Store grants remain isolated. Constraint: Legacy proxy grants require an equal-strength migration path into both canonical plugin domains. Rejected: Reuse runtime authorization for scope assignment | symmetric compatibility would let canonical grants cross plugin boundaries. Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep CanDelegateScope directional even if runtime scope aliases evolve. Tested: go test ./internal/rbac ./internal/server; go vet ./internal/rbac ./internal/server Not-tested: Live migration against an already-issued legacy PAT
Close the cross-repository gaps that made advertised line-user, metadata, chain, Sub-Store, and accounting paths unreachable or partially successful. Both managed and adopted writes now use typed stale-plan approvals, canonical identity, bounded rediscovery, visible auto-sync health, collision-safe UUID recovery, and concurrency-safe read models. Constraint: Legacy proxy grants and migrated ProxyUser rows remain compatible during the alpha transition. Rejected: Reuse runtime scope aliases for delegation or approval | compatibility must not broaden authority. Rejected: Mark approval applied before persistence/reconciliation | it creates false-success states. Confidence: high Scope-risk: broad Reversibility: clean Directive: Preserve typed approval binding, declared-edge precedence, and generation-guarded cache publication. Tested: go test ./... outside sandbox; go vet ./...; targeted race suites for line users, metadata, cache, scopes, UUID restore, usage and autosync Not-tested: HK on-node mutation and Sub-Store backend, deferred to canary
Pin the server module and container build inputs to the merged Design 15 SDK and dashboard commits so CI, release images, and local verification exercise one reproducible compatibility set. Constraint: Server containers embed dashboard and SDK by exact ref. Rejected: Keep feature-head refs | squash merges would make release inputs non-canonical. Confidence: high Scope-risk: narrow Reversibility: clean Directive: Report these exact refs with every alpha deployment. Tested: go test ./...; go vet ./...; SDK and Dashboard merge commits verified through GitHub Not-tested: Container build, pending server branch push and tag
lr00rl
force-pushed
the
feat/scope-vpncore-substore
branch
from
July 22, 2026 13:45
3622215 to
01ec712
Compare
lr00rl
marked this pull request as ready for review
July 22, 2026 13:56
This was referenced Jul 22, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Outcome
Closes the final Design 15 server gaps after the stacked cache slice: canonical vpncore/substore scopes with directed delegation, reachable managed/adopted line-user writes, typed stale-plan approvals, canonical usage accounting, declared-edge precedence, sidecar preservation/reattach, serialized Sub-Store auto-sync status, and concurrency-safe Lines caching.
Release inputs
4a318f246d23875cdd6448d96a62bd87bd67215ca927c6cae45493233a4b5c648bf68bbcba8c5a03(0.2.2-alpha.7)0.2.2-alpha.2Verification
go test ./...(outside sandbox for httptest loopback)go vet ./...go test -racefor line users, metadata, cache, scopes, UUID restore, native usage, and Sub-Store auto-syncgit diff --checkRollout
Merge after #19, then deploy server compatibility before canonical plugin manifests. Roll back plugin manifests first, then dashboard/server compatibility.
Constraint: Existing legacy
proxy:*grants remain runtime-compatible during migration.Confidence: high
Scope-risk: broad
Directive: Do not deploy canonical plugin manifests before this server compatibility bridge.
Tested: Full server test and vet suites plus targeted race coverage.
Not-tested: HK canary, deliberately deferred until the complete stack is merged and packaged.