diff --git a/CHANGELOG.md b/CHANGELOG.md index abb0a88..110e8a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,32 @@ # 更新日志 / Changelog +## 0.4.0 - 2026-10-23 + +**授权决策 `2026-10-auth-1` 落地:原始数据导出回归免费,更新资格改由 +发布时刻判定。**(issue #35 的仓内切片) + +### Added + +- **原始数据导出移出旧 Pro 门禁**:`pcap-export` 与 Wireshark 回放 + (retained)不再要求授权——免费层即可导出自己的捕获数据(PRICING + 免费范围的「raw-data export」落地)。工程报告生成(`report-export`) + 成为付费证据面:按付费范围的「带证据的报告」补上门禁(旧 UI 文案 + 一直宣称 Pro,但实现从未门禁)。 +- **更新资格 = 发布时刻语义**:候选版本的认证 `published_at`(签名 + feed 携带)与 entitlement 的 `updates_through` 判定,**当前日期不再 + 是输入**——窗口内的版本永远可获取,窗口过期不使已装版本失效、 + 不降级、不影响启动。此前按「今天 vs 窗口」判定,截止日次日连窗口 + 内发布的最后一个版本也无法下载。日期粒度的截止扩展到当日结束; + 无可读发布时刻的候选对受门禁安装一律拒绝(fail-closed)。 + `docs/update-contract.md` 记录契约;固定 UTC 边界测试覆盖 + 截止前 1 秒/恰在截止/截止后 1 秒与日期粒度截止。 + +### Changed + +- 产品站(docs/index.html)补 AppImage 安装卡,对照实际发布资产; + `gate-check` 的 `export` 动作由 `report` 取代(原始导出免费后报告 + 是唯一付费导出面)。 + ## 0.3.1 - 2026-10-23 **Linux 分发面对齐 taskly 标杆 + 发布 rivet 切 pin。** 修复 v0.3.0 流水线 diff --git a/PRICING.md b/PRICING.md index b10ac0a..99dc06d 100644 --- a/PRICING.md +++ b/PRICING.md @@ -18,7 +18,7 @@ Engineering value and support effort are higher than for an everyday utility. A ## Free and paid scope -Free / evaluation: Passive capture, protocol decoding, offline import, simulator, parameter previews, existing diagnostics and raw-data export are intended to be free. Moving raw capture export out of its legacy Pro gate still requires implementation; current installers must not be described as already unrestricted. Apache-2.0 source rights remain unchanged. +Free / evaluation: Passive capture, protocol decoding, offline import, simulator, parameter previews, existing diagnostics and raw-data export are intended to be free. Raw capture export (pcap export and Wireshark replay) moved out of its legacy Pro gate in 0.4.0; engineering report generation remains the gated paid evidence surface. Apache-2.0 source rights remain unchanged. Paid: Official Pro GM/slave runtime control, reference-source management, repeatable test orchestration, evidence-backed comparison reports and validated reference combinations. Seats mean named users, not network adapters, devices or concurrent sessions. Only delivered and verified capabilities may appear in an active offer. diff --git a/PRICING.zh-CN.md b/PRICING.zh-CN.md index 673f886..b5ea5bf 100644 --- a/PRICING.zh-CN.md +++ b/PRICING.zh-CN.md @@ -18,7 +18,7 @@ ## 免费与付费边界 -免费 / 评估:被动抓包、协议解码、离线导入、模拟器、参数预览、已有诊断与原始数据导出应免费。原始捕获导出从旧 Pro 门禁移到 Free 的实现尚待完成;不能据此称当前安装包已放开。Apache-2.0 源码权利不变。 +免费 / 评估:被动抓包、协议解码、离线导入、模拟器、参数预览、已有诊断与原始数据导出应免费。原始捕获导出(pcap 导出与 Wireshark 回放)自 0.4.0 起移出旧 Pro 门禁;工程报告生成保持付费证据面。Apache-2.0 源码权利不变。 付费:官方 Pro 的 GM/从钟运行控制、参考源管理、重复测试编排、带证据的比较报告与已验证参考组合;席位是命名用户,不是网卡数/设备数/并发数。仅交付并验证的能力可列在正式 offer。 diff --git a/app/backend.rkt b/app/backend.rkt index 1f221be..a5cf383 100644 --- a/app/backend.rkt +++ b/app/backend.rkt @@ -655,17 +655,16 @@ (count (lambda (d) (hash-ref d 'is_ptp #f)) decoded))) (ok-action (length decoded)))) +;; Raw capture export is free scope (the authorization decision moves it +;; out of the legacy Pro gate); only the engineering report is gated. (define-rpc (pcap-export [path : String] : ActionResult) - (cond - [(not (eq? (gate-check 'export) #t)) (deny-pro (gate-check 'export))] - [else - (with-handlers ([exn:fail? (lambda (e) (fail-action (exn-message e)))]) - (define frames - (reverse - (for/list ([f (in-list (packet-store-snapshot app-packets 999999))]) - (packet->capture-file-frame f)))) - (write-capture-file path frames) - (ok-action (length frames)))])) + (with-handlers ([exn:fail? (lambda (e) (fail-action (exn-message e)))]) + (define frames + (reverse + (for/list ([f (in-list (packet-store-snapshot app-packets 999999))]) + (packet->capture-file-frame f)))) + (write-capture-file path frames) + (ok-action (length frames)))) (define-rpc (wireshark-launch [action : String] [iface : String] : ActionResult) (cond @@ -680,8 +679,7 @@ (log-add! app-logs 'app 'info (format "Wireshark live: iface=~a filter=~a" iface filter)) (ok-action result))] - [(not (eq? (gate-check 'export) #t)) (deny-pro (gate-check 'export))] - [else (ok-action (open-retained-in-wireshark))])) + [(string=? action "retained") (ok-action (open-retained-in-wireshark))])) (define-rpc (series-window [series-id : String] : SeriesWindow) (cond @@ -795,8 +793,13 @@ (write-diagnostic-snapshot! path snapshot) (ok-action (hasheq 'path (path->string path) 'redacted #t)))) +;; The engineering report is the paid evidence surface (PRICING.md's paid +;; scope); raw data access around it stays free. (define-rpc (report-export [path : String] [iface : String] [role : String] [reference : String] : ActionResult) - (with-handlers ([exn:fail? (lambda (e) (fail-action (exn-message e)))]) + (cond + [(not (eq? (gate-check 'report) #t)) (deny-pro (gate-check 'report))] + [else + (with-handlers ([exn:fail? (lambda (e) (fail-action (exn-message e)))]) (define nics (detect-interfaces)) (define chosen-iface (if (string=? iface "") @@ -835,7 +838,7 @@ (write-engineering-report-json! path report) (write-engineering-report-markdown! markdown-path report) (ok-action (hasheq 'json (path->string path) - 'markdown (path->string markdown-path))))) + 'markdown (path->string markdown-path))))])) (define-rpc (params-merge [domain : (Optional Int64)] @@ -930,8 +933,18 @@ (with-handlers ([exn:fail? (lambda (e) (flow-set! 'failed #:error (exn-message e)))]) - (update-prepare! 'download (unbox update-manifest-box) - #:window-open? (gate-update-window-open?))) + (define candidate (unbox update-manifest-box)) + ;; Eligibility is the candidate's authenticated release instant + ;; against the entitlement cutoff — never the current date + ;; (docs/update-contract.md). + (define published-at + (and candidate + (update-manifest-published-at + (update-candidate-manifest candidate)))) + (update-prepare! 'download candidate + #:window-open? + (gate-update-window-open? + #:release-published-at published-at))) (update-state-now)) ;; Applies what is staged, per install shape (deb: pkexec with the diff --git a/app/gate.rkt b/app/gate.rkt index d07629d..080f428 100644 --- a/app/gate.rkt +++ b/app/gate.rkt @@ -3,9 +3,10 @@ ;; Commercial tier gate built on Permit (github.com/turinglambdaai/permit) ;; ;; free — passive listening (capture+decode), offline pcap analysis, -;; simulator, config editor/preview, presets (watch free) +;; simulator, config editor/preview, presets, raw capture +;; export and Wireshark replay ;; pro — engine control (GM/slave), reference-source management, -;; unlimited packet store, pcap/report exports (drive paid) +;; unlimited packet store, engineering reports (drive paid) ;; trial — 14 days of Pro from the moment the user starts it, tracked ;; as permit local-trial state (last_seen high-water mark) ;; @@ -16,7 +17,6 @@ ;; (ins_ + 32 hex) so the vendor can issue credentials bound to it. (require json - racket/date racket/file racket/string permit @@ -178,24 +178,15 @@ (define info (unbox gate-entitlement-box)) (and info (hash-ref info 'updates-through #f))) -;; Whether staging an official update is part of what this install holds. -;; Free and trial always update; a perpetual Pro install updates through -;; its entitlement's updates_through day. -(define (iso-today) - (define d (current-date)) - (format "~a-~a-~a" - (date-year d) - (~r2 (date-month d)) - (~r2 (date-day d)))) - -(define (~r2 n) - (define s (number->string n)) - (if (< (string-length s) 2) (string-append "0" s) s)) - -(define (gate-update-window-open? [today (iso-today)]) +;; Whether staging an official update with the given authenticated +;; release instant is part of what this install holds. Free and trial +;; always update; a perpetual Pro install stages releases published at or +;; before its entitlement's updates_through — the current date plays no +;; role (see updates-window-open?). +(define (gate-update-window-open? #:release-published-at published-at) (updates-window-open? #:pro? (eq? (unbox gate-cache) 'pro) #:updates-through (gate-updates-through) - #:today today)) + #:release-published-at published-at)) ;; Action-level check; returns #t or an error message string. (define (gate-check action) @@ -203,7 +194,7 @@ #t (case action [(engine) "引擎控制(GM / 从钟)是 Pro 功能。可开始 14 天免费试用或输入许可证。"] - [(export) "报文导出与报告生成是 Pro 功能。"] + [(report) "工程报告生成是 Pro 功能。"] [(reference) "外接参考源管理是 Pro 功能。"] [else "此功能需要 Pro 许可证。"]))) diff --git a/app/state.rkt b/app/state.rkt index 2232754..78a678c 100644 --- a/app/state.rkt +++ b/app/state.rkt @@ -33,7 +33,7 @@ settings-set! app-version) -(define app-version "0.3.1") +(define app-version "0.4.0") ;; ---- stores (created once) ----------------------------------------------------- diff --git a/docs/index.html b/docs/index.html index be79f86..41bfb2f 100644 --- a/docs/index.html +++ b/docs/index.html @@ -116,6 +116,10 @@
curl -LO https://github.com/turinglambdaai/gptp-studio/releases/latest/download/gptp-studio-linux-x64.AppImage +chmod +x gptp-studio-linux-x64.AppImage +./gptp-studio-linux-x64.AppImage --doctor +./gptp-studio-linux-x64.AppImage
Bundles its GTK4 dependency closure; no install step.