| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
fix(exver): evaluate ranges against represented release versions (#3796) * fix: accept a flavored dependency in checkDependencies' boolean version check `satisfied()` and `throwIfNotSatisfied()` answer the same question and disagreed when the dependency was installed on a flavor. `installedVersionSatisfied` compared only `installedVersion` against the range, while `throwIfInstalledVersionNotSatisfied` compared `[installedVersion, ...satisfies]`. A flavored version fails every comparison against an unflavored anchor, so the boolean surface reported a `#knots` Bitcoin or a `#quantum` File Browser as unsatisfied while the throwing surface passed and the web UI showed it satisfied. A flavor stands in for the versions it declares in `satisfies`, and the OS ships those on `CheckDependenciesResult` for exactly this purpose, so the boolean path now consults them. The throwing path calls the boolean one rather than restating the predicate, since two spellings of one rule is what let them drift apart. No package is affected today: across 144 `*-startos` repos the only two `checkDependencies` call sites both use `throwIfNotSatisfied()`, and nothing calls `satisfied()` or `installedVersionSatisfied()`. This extends the union semantics the web UI and the throwing path already use. That union is unsound for a negated range — an excluded revision passes through a backwards-compatibility alias — but the semantics is shared with `dep-error.service.ts` and `dry-update.ts`, so narrowing it is a separate change. The divergence dates to 0e598660 and the helper had no behavioral tests. Also corrects the ts-modules scope doc, which said no test runner was wired up here while `make test` has been running start-core's jest suite in CI. * fix: keep the version check total, and correct what this change claims `installedVersionSatisfied` parsed the range before checking that the dependency was installed, so an uninstalled dependency whose range the TS grammar rejects threw where master returned `false`. A guard clause restores that. The changelog and the code comment both said a flavored version fails every comparison against an unflavored anchor. It does not: `!=`, `!` and `*` all match, because they invert or ignore a comparison that is merely undefined. Both now say a flavored version is incomparable to an unflavored one. The union has no flavor guard, so it widens every dependency that declares `satisfies` — Bitcoin Core `31.1:1` now matches a dependent pinning `^28.4:14` through its alias. The entry framed the change as flavor-only; it now names both methods and the whole rule, and `docs/src/dependencies.md` describes the alias mechanism where it documents `versionRange`. Every rescue row paired a flavored version with a single alias, so a flavor-gated union and one that reads only the first alias both passed. A row for an unflavored version rescued by an alias, and a second alias on an existing row, fail both. The version-range message is asserted like its sibling rather than by a bare `toThrow()`. `shared-libs/ts-modules/CONTRIBUTING.md` still said no test runner is wired up — the sentence this branch corrects in the sibling `AGENTS.md`, and the file those docs point at for setup. * test: pin that an absent dependency is answered before the range is parsed The guard that returns `false` before `VersionRange.parse` had no test — every range in the suite parses, so moving the parse back above it left all eight cases green. A case with an unparseable range and no installed version fails against that ordering and passes here. `shared-libs/ts-modules/AGENTS.md`'s "Build & test" block listed no test command, which was consistent while the file said no runner was wired up and is not now that it names one. * fix(exver): a range exclusion holds against every version a release declares `VersionRange.satisfiedByRelease` evaluates a range against a release — its own version together with the versions it declares in `satisfies`. A positive constraint holds when any of them matches; a negation holds only when none does. Evaluating each version against the whole range independently let a release excluded by name pass on any other version it declares, so a dependent pinning `>=2.0:0 && !=2.0:5` accepted the revision it had blacklisted. For one version the new evaluator answers exactly as `satisfies` does. It is now the only implementation of that question. `checkDependencies`, the dependency warnings, the update check and the marketplace preview each carried their own union; the three web callers go through `Exver.releaseSatisfies`. A prerelease segment may mix letters, digits and hyphens, matching `grammar.pest`. `1.0.0-rc1:0` and `1.0.0-alpha-1:0` are versions StartOS accepts and `ExtendedVersion.parse` threw on, so a dependency published on one crashed a dependent's `checkDependencies` with a parse error. A numeric segment with a leading zero is now rejected, as it already was on the OS side. All 592 version and `satisfies` strings published across the three registries still parse and round-trip. The `String` rule the old segment used is gone with it. `compareLexicographic` tested `>` in both branches, so `less` was unreachable and `compareForSort` returned `undefined` from a `1 | 0 | -1` signature — a mixed-flavor sort kept whatever order it arrived in. `Version.compare` read `this.prerelease[1]` where every other index was `i`, so where two segments differed in type at any position but the first, the comparison fell through and reported the versions equal. `shared-libs/ts-modules/lint-staged.config.js` runs prettier with that directory as the working directory, so prettier looked for `.prettierignore` there and found none — reformatting the generated `exver.ts` the root file excludes. It now passes the root ignore file explicitly. The comment above the version check is gone: the rule it stated is documentation on `satisfiedByRelease`, where a reader looks it up. Closes #3797 Closes #3799 Closes #3800 * feat(exver): VersionRange::satisfied_by_release mirrors the TypeScript evaluator The Rust and TypeScript exver libraries answer the same questions, and the release-set evaluation added on the TypeScript side had no counterpart here. A positive constraint holds when any of a release's versions matches; a negation holds only when none of them does. Nothing in the OS evaluates a dependency's `satisfies` set today — it is built in `service/effects/dependency.rs` and shipped to the SDK, which does the matching — so this adds the API rather than changing a call site. `NEQ` compares with `partial_cmp`, matching the arm `satisfies` already uses, so the two agree where `PartialEq` and `Ord` could drift apart. A proptest asserts that a release of one version answers exactly as `ExtendedVersion::satisfies` does, over every generated range. * fix(sdk): CheckDependencies declares the arities its functions have `satisfied` was typed `() => boolean` against an implementation taking an optional package id, and `healthCheckSatisfied` required a health check id its implementation makes optional — one that `pkgSatisfied` itself omits. Both are silent, because a function of fewer parameters is assignable to a type with more, so a package author calling `deps.satisfied('bitcoind')` got `TS2554: Expected 0 arguments, but got 1` for a call that works at runtime, and the only way to check a single dependency was to reimplement the predicate. Widening a declared parameter list breaks no caller and no implementation. * docs(sdk): drop the superseded getServicePortForward changelog entry #3641 added an expanded entry for the same change and left the original in place, so 2.0.10 would ship both — the shorter one is a subset, down to its closing sentence. * fix(exver): keep release semantics through normalization A release is its installed version plus every alias it declares. Evaluation uses negation normal form: positive conjunctions require one alias to witness the whole conjunction, while negative literals veto their branch when any alias matches the positive form. Rust and TypeScript now implement and test that same contract for arbitrary nesting, including empty releases and single-version agreement with ordinary satisfaction. Caret, tilde, and default anchors now expand to the same comparison AST in both implementations before release evaluation. This keeps negated sugar such as !^1:0 identical to !(>=1:0 && <2:0) for multi-version releases without changing ordinary singleton semantics. A truth-table normal form is equivalent for one version but not for this release algebra: !=2:5 expands to <2:5 || >2:5 || !#, which rejects the release [2:5, 2:6] before normalization and accepts it afterwards. normalize() now canonicalizes safe positive subtrees and preserves explicit negation/inequality nodes, so every caller can normalize without changing satisfiedByRelease. Numeric prerelease identifiers now retain exact unbounded decimal identity, ordering, and string serialization in both implementations. TypeScript keeps safe identifiers as numbers and represents only larger parsed identifiers as decimal strings, preserving the existing public union and JSON compatibility without bigint. The ExVer reference now describes release evaluation and corrects the Rust satisfiable/intersects API table. * test(exver): enforce equality and ordering agreement Version implements Eq and Ord independently, so a property test now pins the trait contract across arbitrary pairs and deliberately equivalent trailing-zero representations. The prerelease generator exercises string-backed large numbers and no longer panics when a numeric segment exceeds usize. * fix(exver): equate numeric prerelease representations Number and BigNumber can encode the same identifier, so equality and ordering now compare their decimal values and hashing uses the same numeric domain. A property test pins equality, ordering, and hashing in both directions. * docs(exver): define negative release literals Spell out that a literal is an atomic comparison, flavor test, or wildcard after negation-normal-form rewriting. Define negative literals as negated atoms, with != treated as negated equality, and show their positive forms. * fix: preserve composite exclusions across release aliases | 19 天前 | |
chore(license): fixes from license hygiene audit (#3627) * chore(license): replace proprietary fonts with an open family Proxima Nova (Copyright (c) Mark Simonson, all rights reserved) and MBF Minimal Custom (Copyright (c) MoonBandit, all rights reserved) were tracked in-tree and copied into the ui, setup-wizard, start-tunnel, start-wrt and marketplace bundles by angular.json, under a repository that grants recipients MIT rights to distribute and sublicense. Replace them with Hanken Grotesk (SIL OFL 1.1). One variable face covers the whole 100-900 range the seven static Proxima weights were serving, so the two woff2 subsets are 54 KB against the 460 KB they replace. The MBF face was declared in start-tunnel but no rule ever applied the family, so it is dropped rather than replaced. * chore(license): carve the GPL-2.0 OpenWrt material out of start-wrt's MIT grant projects/start-wrt/LICENSE claimed MIT over the whole project, but sixteen files under openwrt-overlay/ carry an explicit SPDX-License-Identifier: GPL-2.0-only header naming SpaceMiT Ltd. or OpenWrt.org, and openwrt-patches/ are derivative works of GPL-2.0 OpenWrt sources. GPL-2.0 cannot be relicensed downstream, so the MIT grant was offering rights Start9 does not hold. Add COPYING (GPL-2.0) plus a README to each directory recording provenance and the GPL-2.0 §3 source obligation, and scope the MIT grant in the LICENSE and README to exclude them. CONTRIBUTING described openwrt-overlay/ as "the Start9 additions"; it is mostly SpaceMiT's BSP, so say so. * chore(license): attribute vendored third-party code imbl-value's src/de.rs is 84% line-identical to serde_json's src/value/de.rs (longest identical run 107 lines), ser.rs 80% and index.rs 74%, and macros.rs is serde_json's json! muncher with its comments intact — yet LICENSE named only Start9 and AGENTS.md asserted the impls were not serde_json's. All the upstreams here are MIT or MIT-compatible, so this is notice compliance, not relicensing. - imbl-value: credit Erick Tryzelaar and David Tolnay in LICENSE, record the derivation in README, and correct the AGENTS.md bullet. - patch-db/json-patch: a fork of idubrov/json-patch with serde_json swapped for imbl-value + json-ptr, shipping no license text despite declaring dual terms. Add LICENSE-MIT and the verbatim LICENSE-APACHE, a README recording the fork, and normalize the SPDX expression to "MIT OR Apache-2.0". - jsonpath: fill in the MIT template placeholders left as "[2019] [Changseok Han]" and credit the upstream in the README. - init_resize.sh: name RPi-Distro/raspi-config, which it derives from. json-patch and jsonpath_lib are also set publish = false: both sit at crates.io names owned by their upstreams, so publishing a diverged fork from here would be wrong even if it were possible. * chore(license): declare MIT on every manifest, ship it with published crates Five Cargo manifests (backup-fs, patch-db-util, the three start-wrt crates) and eleven package.json files declared no license at all, and the workspace root has no [workspace.package] table to inherit one from, so tooling reported them as unlicensed. Declare MIT on each. exver and rpc-toolkit are published to crates.io but carried no license text in their tarballs; give them a LICENSE. Normalize the copyright holder across the existing files, which variously read "Start9", "Start9 Labs" and "Start9 Labs, Inc.", and rename yasi's LICENSE.md so cargo packages it by convention. The upload-each action's committed ncc bundle inlined 97 dependencies with their notices stripped; build it with --license so the per-dependency notices are generated and committed alongside. The bundle itself is byte-identical. * chore(license): add NOTICE.md and state the licensing policy Nothing in the repo said what "everything is MIT" excludes, so the claim could not be checked. NOTICE.md is now the complete list of files under other terms — if something is not named there, it is MIT — and the root LICENSE, README and the StartOS architecture doc point at it. Also: - CONTRIBUTING gains an inbound-licensing statement and a rule that vendored code keeps its notice and lands in NOTICE.md in the same PR. - .deb packages are built with a usr/share/doc/<pkg>/copyright file, which Debian policy requires and which the hand-written control block omitted. - deny.toml moves to the workspace root and drops copyleft/unlicensed/ allow-osi-fsf-free, removed from cargo-deny's schema in 0.14. Note nothing in CI runs it yet, so it remains documentation rather than a gate. - The Intel BIOS capsule mirrored for the discontinued 2023 Server One is attributed to Intel on the page that serves it. It is Intel's, not ours, and the architecture doc no longer implies the shipped image is MIT end to end. * chore(license): sync lockfiles with the added license fields npm records the root package's license in package-lock.json, so declaring it in package.json leaves the lockfile out of sync — which is exactly what CI's `npm ci` drift gate rejects. Five lockfiles, one line each, no dependency churn. * chore(license): taplo-format deny.toml The relocated file landed at the repo root without going through taplo, whose reorder_keys sorts each [[licenses.clarify]] table's keys. Caught by CI's format-check, which I hadn't run locally because it needs the fmt container. * chore(license): make deny.toml describe the tree it actually governs Nothing had ever run this policy, so it had drifted from reality in both directions. Ran cargo-deny against the real dependency graph: - LGPL-3.0, OpenSSL and Unicode-DFS-2016 were allowed but appear nowhere. LGPL is the one that mattered: allowing it invited a copyleft dependency that would have been incompatible with shipping start-core as MIT. - The webpki and ring clarifications are dead — webpki is gone (rustls-webpki now) and ring declares "Apache-2.0 AND ISC" itself. - Four permissive licenses genuinely in the tree were missing, so 25 crates were rejected for no good reason: Unicode-3.0 (the ICU stack), CDLA-Permissive-2.0 (webpki-roots), BSL-1.0 (xxhash-rust, lazy-bytes-cast) and 0BSD (quoted_printable). MPL-2.0 stays allowed and is now explained: its copyleft is per-file, so linking imbl and friends into an MIT binary is fine as long as we don't modify them. This leaves two genuine GPL-3.0-or-later rejections, which need code changes rather than a policy change, so the CI gate lands with that fix. * chore(license): revert the overreach in this branch Review of my own decisions found several that were wrong or went further than the evidence supported. Reverting them. - Restore "LGPL-3.0" to deny.toml. My commit message claimed allowing it was "incompatible with shipping start-core as MIT". That is wrong: LGPL-3.0 §4 expressly permits combining the library with a work conveyed under other terms, subject to notice and relink conditions. Worse, the entry was not drift — 5b22d0a3b (Aiden McClelland, 2021-06-17) added it in the commit that created the file, as a deliberate carve-out. An unmatched allowance is only a warning, so removing it bought nothing and would have hard-rejected a future LGPL dependency that is in fact perfectly usable. - Restore the root LICENSE to byte-canonical MIT. Editing the license body to add a carve-out risks breaking automated license detection, and the carve-out already lives in README.md and NOTICE.md. Same for start-wrt's LICENSE. - Restore extract-ikconfig. Deleting a working debugging tool from the image was a functional change made for a licensing reason that a NOTICE entry solves. - Restore jsonpath's LICENSE verbatim. Filling in a third party's copyright placeholders is not ours to do; the clarification belongs in the README. - CONTRIBUTING lumped LGPL in with GPL/AGPL as forbidden. Corrected: GPL/AGPL can't be linked into our binaries, LGPL and MPL-2.0 can, with obligations. - NOTICE claimed to be "the complete list" and that anything unlisted is MIT. Softened — I can't guarantee completeness. - Moved brand marks out of "Not MIT" into their own Trademarks section. Trademark is not copyright and is not granted or withheld by a copyright license, so listing logos as a licensing exception was a category error. - The MPL note said obligations attach only if we modify the sources. They attach on distribution (§3.2), modified or not. - The overlay README asserted every unheadered file was GPL "including the Start9-authored ones, which are derivative works". A new file in an OpenWrt tree is not automatically derivative; that gave away Start9's own copyright by assertion. Now stated as a deliberate contribution choice. Also dropped "the one exception" (NOTICE lists several) and softened GPL-2.0-only to GPL-licensed, since the tree mixes -only and -or-later. - Restore the start-wrt font-weight design comment, reworded for the variable face rather than deleted. * refactor(core): replace socks5-impl with fast-socks5 socks5-impl is GPL-3.0-or-later, and it was a direct dependency of start-core, so every product binary linking start-core would have to be conveyed under GPL-3.0. No permissive version exists upstream — the current 0.9.6 is still GPL-3.0-or-later — so this is a swap rather than a bump. fast-socks5 (MIT) covers the same ground: read_command() hands back the target before connecting, which is what lets us keep intercepting .onion (tunnel via the tor service's SOCKS proxy) and .local (resolve over mDNS), and get_socket() unwraps the client tunnel to a plain TcpStream so the keepalive still applies. BIND and UDP ASSOCIATE are still answered CommandNotSupported. The proxy had no test coverage, so this adds three: a round trip through the proxy to an echo server, an unreachable target refused rather than hung, and BIND/UDP rejected. * refactor(start-wrt): replace tracing-rfc-5424 with syslog-tracing, gate licenses in CI tracing-rfc-5424 is GPL-3.0-or-later — the last crate in the tree whose terms we can't meet while conveying our binaries under MIT. syslog-tracing (MIT) writes through libc's syslog(), which lands in the same /dev/log that the old UnixSocket transport targeted, so logread still sees the entries. Its MakeWriter maps tracing levels to syslog severities via make_writer_for. init_logging took a name it then ignored; syslog-tracing can use it as the openlog identity, so startwrt-cli and startwrt-ctrld are now distinguishable in logread instead of sharing one tag. The startwrt-activity marker activity.rs greps for is in the message body, so it is unaffected. Timestamps and tag are dropped from the formatter because syslogd adds its own. With that, `cargo deny check licenses` passes, so it becomes a CI job. LGPL-3.0 stays allowed and simply reports as an unmatched allowance. | 1 个月前 | |
docs: delete scope-doc text with no live producer (#3728) * docs(sdk): drop the fleet-provenance clause from the description advice "Two more characters' worth of advice, both from descriptions already in the registries" — the provenance half is a claim about what the fleet's short descriptions look like right now, with nothing keeping it true. It is already only partly accurate: 4 of the 107 packages with an en_US short open with the service name, which is the pattern the first bullet tells you to avoid. The two bullets it introduces both have live producers and stay exactly as written. Split out from the rest of the packaging-guide cruft audit because this paragraph exists only on master — the published guide does not carry it, so it cannot be fixed on live-docs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: delete scope-doc text with no live producer Audited all 65 AGENTS.md / ARCHITECTURE.md / CONTRIBUTING.md files across every scope against one test: a sentence citing what not to do, what not to include, or a mistake once made must name a live producer — a scaffold that emits it, a neighbour someone would copy, a tool that does it unless you intervene, or an obvious-but-wrong fix someone would reach for. No producer, delete. Facts that are simply wrong: - start-registry's CONTRIBUTING said its Cargo version "tracks the OS release line — don't bump it independently", while its own AGENTS.md one directory over says the opposite. The crate is 1.0.2 and StartOS is 0.4.0.2, so the CONTRIBUTING rule is the retired one. Its "(currently 1.0.0)" had drifted too. - rpc-toolkit's CONTRIBUTING described a `rustfmt.toml` the crate does not ship; only the repo root has one. - start-sdk's build table documented `make dist`, which is not a target in that Makefile (start-core's `make dist`, referenced further down the same file, is real and stays). - The root ARCHITECTURE tree put `apt/` under projects/start-os/; it is at the repo root. - shared-libs' CONTRIBUTING said ts-modules' contents are Angular libraries; it also holds the non-Angular start-core. - start-registry's ARCHITECTURE counted "all five product binaries"; the root AGENTS.md counts six. - start-sdk's ARCHITECTURE listed AGENTS.md twice in Further reading. Migration narration whose migration is over: Four separate stale-path notes mapped the pre-monorepo root layout (`core/`, `web/`, `sdk/`, `patch-db/`, `container-runtime/`). The root AGENTS.md keeps one — `core/src/` is still referenced live in projects/start-os/DEV_TODO.md, so the mapping is still reachable — and the copies in start-cli, container-runtime and shared-libs go, along with "Internally unchanged from the old `core/` crate", the start-fs migration note, the retired start-os submodule's workspace Cargo.toml, and the `base/lib/...` import shape. The retired `next/patch` | `next/minor` | `next/major` prohibition goes from AGENTS.md; the mapping line in the root CONTRIBUTING.md stays, which is the one line the still-reachable-artifact rule allows. Counts and in-progress markers: `~430 tests` (twice), `11 modules` (twice), `~28 utility modules`, `~117-line`, `~2200 lines`, `all five product binaries`, `currently 1.0.0`, `3 small build-infra patches`, `(currently by start-core)`, `(currently just bitcoin-guides)`, `(currently the Angular libs shared and marketplace)` (twice), the SDK/OS version pair, `being replaced`, `being phased out`, the per-scope CONTRIBUTING migration tally (three copies), the patch-db repo "is being retired" (the repo is still live and was pushed to after the claim was written), and two notes recording which warnings a crate happened to emit. Also drops a commented-out list of ten aspirational locales, a prohibition against putting files directly in shared-libs/ (nothing but doc files ever has, across the directory's whole history), and a prohibition against nesting tab groups more than one level, which restates the positive rule in the sentence before it. Includes the fleet-provenance clause in the packaging guide's manifest.md, which can only be fixed here — the rest of that audit is on live-docs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Matt Hill <9935159+MattDHill@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> | 1 个月前 | |
fix(start-core): make install rollback crash-recoverable, and snapshot a stopped service (#3598) * fix(start-core): make install rollback crash-recoverable, and snapshot a stopped service A user cancelled a long package update and lost that service's database. The rollback is what deletes data: `restore_volumes_from_install_backup` deleted the live volume root and then renamed the backup into place, so an interruption between the two left the service with neither — and because `handle_installed` and `Bind::pre_mount` recreate a missing volume dir as an empty one, the result was indistinguishable from a completed rollback. The next update then discarded the surviving backup as stale, which is where the data actually went. Restore is now a two-rename swap: move the live root to `<pkg>.restore-old`, rename the backup into place, drop the aside tree. Between the renames both copies exist, and `<pkg>.restore-old` is a marker that survives an empty-skeleton recreation, so `resolve_pending_restore` can finish any interruption point deterministically instead of guessing which tree is authoritative. It runs from `ensure_volume_root` — the funnel every path uses before it trusts or creates the live root — as well as from the snapshot, the boot sweep, and `remove_install_backup`, which now refuses to discard a backup while a restore is in flight. The snapshot no longer deletes the previous rollback point as its first act: it snapshots to `<pkg>.install-backup-tmp` and swaps, so the old backup is only dropped once its replacement exists. A rollback that fails is now fatal to the load and notifies the user, rather than being swallowed by `log_err` and then having its rollback point deleted by the `Ok` path that followed. A failed first-time install over pre-existing data keeps those volumes for the restore instead of deleting them first. The boot sweep is no longer readdir-order dependent: it resolves every pending restore before any branch inspects a backup, so the orphan-reaping arm can't delete a backup that an unvisited marker still depends on. Finally, `ServiceRef::quiesce` stops the service's main chain before the snapshot, leaving the package's uninit for `uninstall`. The snapshot already predated uninit and is atomic, so this is not about the snapshot's internal consistency: it means nothing is writing to the tree a later rollback will rename or delete, formats that aren't crash-safe on their own survive, and the rollback point is the state the user had when they pressed update. It writes nothing to the status — clearing `started` would let the actor race a restart back in, and setting `desired` to Stopped would leave the service stopped after a successful update — guards on `is_initialized` (an uninitialized container's `stop` throws), and is bounded, because proceeding un-quiesced beats hanging an update on a wedged daemon. * refactor(start-core): add TypedDbWatch::wait_for and use it for db state waits Three places hand-rolled the same peek-then-changed() loop to block until the database reached some state, and two more waited on a single revision as a proxy for a condition. wait_for is that loop: it peeks and marks seen before awaiting, so it can neither miss a revision nor spin on the free pass DbWatch hands an unseen value — which the two tunnel loops were doing, since they peeked without marking. The predicate takes the deserialized value rather than the model because a fallible predicate over &T::Model cannot be inferred at the call site: with the error generic (E: From<patch_db::Error>) start-core offers rustc several candidate impls, so every call needs a turbofish. Taking T instead keeps the predicate infallible and still propagates deserialization failures. The two revision-proxy waits change behavior. add_tunnel gated its default-outbound write on any revision under the new interface's ipInfo, which a write that left the address absent satisfies; it now waits for the address itself. NetworkInterfaceController::forget returned once anything under gateways changed, so a concurrent update to a different gateway could let it return before its own removal was durable; it now waits for its key to be gone. * fix(start-core): give DesiredStatus::Updating an on_complete run state Updating now records whether the service was running when the update began, exactly like BackingUp: stop()/start() during an update flip the payload instead of the variant, and init() restores Running or Stopped accordingly — so a power loss mid-update boots the service back to the state the user last asked for. --------- Co-authored-by: Aiden McClelland <me@drbonez.dev> | 1 个月前 | |
docs: delete scope-doc text with no live producer (#3728) * docs(sdk): drop the fleet-provenance clause from the description advice "Two more characters' worth of advice, both from descriptions already in the registries" — the provenance half is a claim about what the fleet's short descriptions look like right now, with nothing keeping it true. It is already only partly accurate: 4 of the 107 packages with an en_US short open with the service name, which is the pattern the first bullet tells you to avoid. The two bullets it introduces both have live producers and stay exactly as written. Split out from the rest of the packaging-guide cruft audit because this paragraph exists only on master — the published guide does not carry it, so it cannot be fixed on live-docs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: delete scope-doc text with no live producer Audited all 65 AGENTS.md / ARCHITECTURE.md / CONTRIBUTING.md files across every scope against one test: a sentence citing what not to do, what not to include, or a mistake once made must name a live producer — a scaffold that emits it, a neighbour someone would copy, a tool that does it unless you intervene, or an obvious-but-wrong fix someone would reach for. No producer, delete. Facts that are simply wrong: - start-registry's CONTRIBUTING said its Cargo version "tracks the OS release line — don't bump it independently", while its own AGENTS.md one directory over says the opposite. The crate is 1.0.2 and StartOS is 0.4.0.2, so the CONTRIBUTING rule is the retired one. Its "(currently 1.0.0)" had drifted too. - rpc-toolkit's CONTRIBUTING described a `rustfmt.toml` the crate does not ship; only the repo root has one. - start-sdk's build table documented `make dist`, which is not a target in that Makefile (start-core's `make dist`, referenced further down the same file, is real and stays). - The root ARCHITECTURE tree put `apt/` under projects/start-os/; it is at the repo root. - shared-libs' CONTRIBUTING said ts-modules' contents are Angular libraries; it also holds the non-Angular start-core. - start-registry's ARCHITECTURE counted "all five product binaries"; the root AGENTS.md counts six. - start-sdk's ARCHITECTURE listed AGENTS.md twice in Further reading. Migration narration whose migration is over: Four separate stale-path notes mapped the pre-monorepo root layout (`core/`, `web/`, `sdk/`, `patch-db/`, `container-runtime/`). The root AGENTS.md keeps one — `core/src/` is still referenced live in projects/start-os/DEV_TODO.md, so the mapping is still reachable — and the copies in start-cli, container-runtime and shared-libs go, along with "Internally unchanged from the old `core/` crate", the start-fs migration note, the retired start-os submodule's workspace Cargo.toml, and the `base/lib/...` import shape. The retired `next/patch` | `next/minor` | `next/major` prohibition goes from AGENTS.md; the mapping line in the root CONTRIBUTING.md stays, which is the one line the still-reachable-artifact rule allows. Counts and in-progress markers: `~430 tests` (twice), `11 modules` (twice), `~28 utility modules`, `~117-line`, `~2200 lines`, `all five product binaries`, `currently 1.0.0`, `3 small build-infra patches`, `(currently by start-core)`, `(currently just bitcoin-guides)`, `(currently the Angular libs shared and marketplace)` (twice), the SDK/OS version pair, `being replaced`, `being phased out`, the per-scope CONTRIBUTING migration tally (three copies), the patch-db repo "is being retired" (the repo is still live and was pushed to after the claim was written), and two notes recording which warnings a crate happened to emit. Also drops a commented-out list of ten aspirational locales, a prohibition against putting files directly in shared-libs/ (nothing but doc files ever has, across the directory's whole history), and a prohibition against nesting tab groups more than one level, which restates the positive rule in the sentence before it. Includes the fleet-provenance clause in the packaging guide's manifest.md, which can only be fixed here — the rest of that audit is on live-docs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Matt Hill <9935159+MattDHill@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> | 1 个月前 | |
docs: delete scope-doc text with no live producer (#3728) * docs(sdk): drop the fleet-provenance clause from the description advice "Two more characters' worth of advice, both from descriptions already in the registries" — the provenance half is a claim about what the fleet's short descriptions look like right now, with nothing keeping it true. It is already only partly accurate: 4 of the 107 packages with an en_US short open with the service name, which is the pattern the first bullet tells you to avoid. The two bullets it introduces both have live producers and stay exactly as written. Split out from the rest of the packaging-guide cruft audit because this paragraph exists only on master — the published guide does not carry it, so it cannot be fixed on live-docs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: delete scope-doc text with no live producer Audited all 65 AGENTS.md / ARCHITECTURE.md / CONTRIBUTING.md files across every scope against one test: a sentence citing what not to do, what not to include, or a mistake once made must name a live producer — a scaffold that emits it, a neighbour someone would copy, a tool that does it unless you intervene, or an obvious-but-wrong fix someone would reach for. No producer, delete. Facts that are simply wrong: - start-registry's CONTRIBUTING said its Cargo version "tracks the OS release line — don't bump it independently", while its own AGENTS.md one directory over says the opposite. The crate is 1.0.2 and StartOS is 0.4.0.2, so the CONTRIBUTING rule is the retired one. Its "(currently 1.0.0)" had drifted too. - rpc-toolkit's CONTRIBUTING described a `rustfmt.toml` the crate does not ship; only the repo root has one. - start-sdk's build table documented `make dist`, which is not a target in that Makefile (start-core's `make dist`, referenced further down the same file, is real and stays). - The root ARCHITECTURE tree put `apt/` under projects/start-os/; it is at the repo root. - shared-libs' CONTRIBUTING said ts-modules' contents are Angular libraries; it also holds the non-Angular start-core. - start-registry's ARCHITECTURE counted "all five product binaries"; the root AGENTS.md counts six. - start-sdk's ARCHITECTURE listed AGENTS.md twice in Further reading. Migration narration whose migration is over: Four separate stale-path notes mapped the pre-monorepo root layout (`core/`, `web/`, `sdk/`, `patch-db/`, `container-runtime/`). The root AGENTS.md keeps one — `core/src/` is still referenced live in projects/start-os/DEV_TODO.md, so the mapping is still reachable — and the copies in start-cli, container-runtime and shared-libs go, along with "Internally unchanged from the old `core/` crate", the start-fs migration note, the retired start-os submodule's workspace Cargo.toml, and the `base/lib/...` import shape. The retired `next/patch` | `next/minor` | `next/major` prohibition goes from AGENTS.md; the mapping line in the root CONTRIBUTING.md stays, which is the one line the still-reachable-artifact rule allows. Counts and in-progress markers: `~430 tests` (twice), `11 modules` (twice), `~28 utility modules`, `~117-line`, `~2200 lines`, `all five product binaries`, `currently 1.0.0`, `3 small build-infra patches`, `(currently by start-core)`, `(currently just bitcoin-guides)`, `(currently the Angular libs shared and marketplace)` (twice), the SDK/OS version pair, `being replaced`, `being phased out`, the per-scope CONTRIBUTING migration tally (three copies), the patch-db repo "is being retired" (the repo is still live and was pushed to after the claim was written), and two notes recording which warnings a crate happened to emit. Also drops a commented-out list of ten aspirational locales, a prohibition against putting files directly in shared-libs/ (nothing but doc files ever has, across the directory's whole history), and a prohibition against nesting tab groups more than one level, which restates the positive rule in the sentence before it. Includes the fleet-provenance clause in the packaging guide's manifest.md, which can only be fixed here — the rest of that audit is on live-docs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Matt Hill <9935159+MattDHill@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> | 1 个月前 | |
fix(net): preserve mDNS enablement without LAN IPs (#4035) * fix(net): preserve mDNS enablement without LAN IPs Helix-Harness: pi Helix-Model: openai-codex/gpt-5.6-sol * fix(start-core): keep a service's .local address enabled without lan ips A service's `.local` row was built only from gateways holding `ip_info`, so it left `available` whenever the network was down: at the boot seed, and, since the network-settle change, on link loss too. Packages comparing a stored URL against their filled addresses then saw it as removed and raised a critical task asking for the URL the user already chose. `mdns_gateways` now takes the binding's previous address table, and a gateway without `ip_info` keeps the membership it had there. `device_type` lives inside `ip_info`, so a disconnected gateway cannot otherwise be told from any other interface. The row goes once the gateway leaves the table. The SDK prunes `.local` only when LAN IP rows exist on its gateways and every one of them is disabled, rather than whenever none is enabled. A private IP's state becomes an override against its `.local` row: explicit on (`lan_enabled`, new), explicit off (`disabled`), or neither, in which case it follows `.local`. That makes `.local`'s setting the default for an address the server is assigned later with nothing written at discovery, which matters because the boot seed makes every address look newly discovered. `enabled` could not hold the explicit-on record: `set_gua_wan` and `resolve_nonssl_gua` both remove a LAN GUA from it. On a non-SSL port there is no SNI, so an enabled IP serves the name whatever its switch says; `.local` reads as on there while any IP it resolves to is on. The non-SSL LAN group reads and writes through the same effective state, and a `.local` toggle re-asserts a linked gateway's group at its private domain's state so the linked IPv4 keeps following the domain. The UI shows the backend's state through a shared `isAddressEnabled` in place of its own copy, and the `.local` switch is interactive, locked only while an IP holds it on. `v0_4_0_2::up` backfills `lanEnabled` because the UI reads raw patch-db JSON, and its migration revision moves to 3 so servers already on alpha re-run it. * fix(start-core): count public GUAs for mDNS reachability Helix-Harness: pi Helix-Model: openai-codex/gpt-5.6-sol * fix(start-core): let the .local switch always be switched off An enabled LAN IP on a non-SSL port reads `.local` as on, so with the IP left alone a request to disable `.local` had no visible effect and the UI locked the switch. Disabling `.local` there now takes what holds it on off with it: a gateway whose LAN level a private domain links moves as that group does, and every other LAN IP it resolves to loses its explicit-on override and follows `.local` off. Re-enabling `.local` brings the followers back. A public GUA no longer holds `.local` on. A `.local` switch must not un-publish a WAN address, and nothing else may leave the switch stuck. `mdnsResolvable` still counts an enabled public GUA as a way to reach an enabled `.local`; the test that had one hold a disabled `.local` on now covers that case instead. The UI's `locked` row state is gone, and the mock backend mirrors the cascade. * fix(start-sdk): list every address the user has enabled A filled address pruned an enabled `.local` while no enabled IP could reach it. The prune was a second notion of "on" beside the switch, with its own inputs, so the Interfaces tab and a package could disagree about the same address. It was also wrong where it fired: a forward is built per gateway and a `.local` vhost answers on every subnet IP of its gateways, so the name was reachable with its LAN IPs switched off. The switch is the answer. `enabledAddresses` is the rows `isAddressEnabled` admits, and `utils.mdnsResolvable`, exported since 2.0.0 and used by nothing else, is removed. That drops the public-GUA counting it had just gained and the two tests for it. * docs(start-os): say that a public gua outlasts a disabled .local On a non-SSL port `.local` resolves to an enabled public GUA, so it reaches the service from the LAN while its switch reads off. The switch leaves the GUA alone because it must not un-publish a WAN address. The Interfaces page says so in its GUA note, and the rule carries the fact in both languages: the omission reads as a bug and has already been "fixed" once. * feat(start-os): warn on a .local address whose ips are all disabled With the switch as the single answer, `.local` can be on beside a gateway's IP addresses with every one of them off, which is a valid setting and almost never what was meant: those are the addresses the name resolves to. The row says so with a warning icon and tooltip. It is judged per gateway table and per port, against the rows the name resolves to there: the LAN IPs, and a public GUA. A table with no such rows is a disconnected gateway and shows nothing. * fix(start-os): keep the .local ip warning to non-ssl rows On a TLS port the `.local` vhost is routed by SNI and answers whatever the IP switches say, so an enabled `.local` beside disabled IPs is nothing to warn about there. The warning belongs to the forwarded port, where the name is only ever reached through those addresses. * fix(start-core): forward a lan ip only through its own enabled row A forwarded port admitted a LAN address if any enabled private row named its gateway, and each such row was expanded into every subnet address of that gateway. The `.local` row is one of them, so with `.local` on, switching a LAN IP off closed nothing: the address stayed in `private_ips` and the forward kept answering on it. The same expansion fed port ranges. An IP row now admits its own address. A private domain still admits its gateways' addresses: on a non-SSL port it and the bare LAN IPv4 are one group and are toggled together, and a domain added while the IPv4 follows a disabled `.local` must still resolve somewhere. `.local` admits nothing of its own. It spans gateways and may be on beside a disabled IP, which only means something if it cannot hold that IP open. `.local` on with every LAN IP off is now unreachable on a forwarded port, which is what its row's warning says. * fix(start-core): answer bare-ip tls only on enabled ssl-port ips The SSL `*` vhost took its LAN addresses from the gateways of every enabled private row, names and plain-port rows included. With `.local` on, a disabled bare IP still answered TLS that named no host, and an IP enabled only on the plain port opened the TLS port too. It now answers on its enabled SSL-port IP rows and nothing else, scoped the way `ssl_vhost_public_v4` already scopes the WAN side. A name keeps its own vhost and its own gateways' addresses, and the listener binds the union, so an address whose bare-IP row is off still answers the `.local` SNI and only that. --------- Co-authored-by: Aiden McClelland <me@drbonez.dev> | 9 小时前 | |
docs: delete scope-doc text with no live producer (#3728) * docs(sdk): drop the fleet-provenance clause from the description advice "Two more characters' worth of advice, both from descriptions already in the registries" — the provenance half is a claim about what the fleet's short descriptions look like right now, with nothing keeping it true. It is already only partly accurate: 4 of the 107 packages with an en_US short open with the service name, which is the pattern the first bullet tells you to avoid. The two bullets it introduces both have live producers and stay exactly as written. Split out from the rest of the packaging-guide cruft audit because this paragraph exists only on master — the published guide does not carry it, so it cannot be fixed on live-docs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * docs: delete scope-doc text with no live producer Audited all 65 AGENTS.md / ARCHITECTURE.md / CONTRIBUTING.md files across every scope against one test: a sentence citing what not to do, what not to include, or a mistake once made must name a live producer — a scaffold that emits it, a neighbour someone would copy, a tool that does it unless you intervene, or an obvious-but-wrong fix someone would reach for. No producer, delete. Facts that are simply wrong: - start-registry's CONTRIBUTING said its Cargo version "tracks the OS release line — don't bump it independently", while its own AGENTS.md one directory over says the opposite. The crate is 1.0.2 and StartOS is 0.4.0.2, so the CONTRIBUTING rule is the retired one. Its "(currently 1.0.0)" had drifted too. - rpc-toolkit's CONTRIBUTING described a `rustfmt.toml` the crate does not ship; only the repo root has one. - start-sdk's build table documented `make dist`, which is not a target in that Makefile (start-core's `make dist`, referenced further down the same file, is real and stays). - The root ARCHITECTURE tree put `apt/` under projects/start-os/; it is at the repo root. - shared-libs' CONTRIBUTING said ts-modules' contents are Angular libraries; it also holds the non-Angular start-core. - start-registry's ARCHITECTURE counted "all five product binaries"; the root AGENTS.md counts six. - start-sdk's ARCHITECTURE listed AGENTS.md twice in Further reading. Migration narration whose migration is over: Four separate stale-path notes mapped the pre-monorepo root layout (`core/`, `web/`, `sdk/`, `patch-db/`, `container-runtime/`). The root AGENTS.md keeps one — `core/src/` is still referenced live in projects/start-os/DEV_TODO.md, so the mapping is still reachable — and the copies in start-cli, container-runtime and shared-libs go, along with "Internally unchanged from the old `core/` crate", the start-fs migration note, the retired start-os submodule's workspace Cargo.toml, and the `base/lib/...` import shape. The retired `next/patch` | `next/minor` | `next/major` prohibition goes from AGENTS.md; the mapping line in the root CONTRIBUTING.md stays, which is the one line the still-reachable-artifact rule allows. Counts and in-progress markers: `~430 tests` (twice), `11 modules` (twice), `~28 utility modules`, `~117-line`, `~2200 lines`, `all five product binaries`, `currently 1.0.0`, `3 small build-infra patches`, `(currently by start-core)`, `(currently just bitcoin-guides)`, `(currently the Angular libs shared and marketplace)` (twice), the SDK/OS version pair, `being replaced`, `being phased out`, the per-scope CONTRIBUTING migration tally (three copies), the patch-db repo "is being retired" (the repo is still live and was pushed to after the claim was written), and two notes recording which warnings a crate happened to emit. Also drops a commented-out list of ten aspirational locales, a prohibition against putting files directly in shared-libs/ (nothing but doc files ever has, across the directory's whole history), and a prohibition against nesting tab groups more than one level, which restates the positive rule in the sentence before it. Includes the fleet-provenance clause in the packaging guide's manifest.md, which can only be fixed here — the rest of that audit is on live-docs. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Matt Hill <9935159+MattDHill@users.noreply.github.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> | 1 个月前 |
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
| 19 天前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 1 个月前 | ||
| 9 小时前 | ||
| 1 个月前 |