Repository navigation
fix(langselector): install missing language packages - #1280
Conversation
Reviewer's GuideFixes language support installation by correctly detecting missing packages, using system-bus NetworkManager global connectivity, and preserving start notifications for all language switches; the separate dde-api batch-query change must also be integrated to address slow package discovery. Sequence diagram for language switching and support package installationsequenceDiagram
participant User
participant LangSelector
participant LanguageSupport
participant NetworkManager
participant Lastore
participant Notifications
User->>LangSelector: setLocale(locale)
LangSelector->>LanguageSupport: ByLocale(locale, false)
LanguageSupport-->>LangSelector: missing packages
LangSelector->>NetworkManager: PropState().Get(0)
NetworkManager-->>LangSelector: State
LangSelector->>Notifications: sendNotify(start notification)
LangSelector->>LangSelector: generate locale
alt missing packages and State == 70
LangSelector->>LanguageSupport: ByLocale(locale, false)
LanguageSupport-->>LangSelector: packages to install
LangSelector->>Lastore: InstallPackage(packages)
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
fda232b to
951afa5
Compare
1. A nonempty ByLocale result means packages are missing, so the inverted check treated them as already installed and nothing was ever installed; decide with needsInstall instead. 2. Read State from NetworkManager on the system bus instead of the session org.deepin.dde.Network1, whose dde-network-core 2.0 compatibility stub always returns 0 and made the daemon believe it was offline. 3. Require NM_STATE_CONNECTED_GLOBAL (70) before installing, because local or site connectivity alone cannot reach the package mirrors. 4. Send the start notification even when no package needs installation. 5. Reuse getInstallLangSupportPackages in the install path, removing the duplicated query code. Log: Switching the system language installs the missing language packages again. Influence: Language packages are installed when the internet is reachable. fix(langselector): 联网时安装缺失的语言支持包 1. ByLocale 返回非空即表示有包尚未安装,原判断写反导致被当成已安装,从不安装;改用 needsInstall 判断。 2. 改为读取系统总线上 NetworkManager 的 State,不再依赖 dde-network-core 2.0 中固定返回 0 的会话 org.deepin.dde.Network1 兼容层,该兼容层使程序始终认为断网。 3. 只有 NM_STATE_CONNECTED_GLOBAL(70)才安装,仅本地或站点连通无法访问软件源。 4. 没有缺包时也发送开始通知。 5. 安装流程复用 getInstallLangSupportPackages,去掉重复的查询代码。 Log: 切换系统语言后能够正常安装缺失的语言支持包。 PMS: BUG-379697 PMS: BUG-379687 PMS: BUG-379685 Influence: 联网可达时自动补装语言支持包。
951afa5 to
eaf0878
Compare
There was a problem hiding this comment.
Hey - I've found 1 issue
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location path="langselector1/locale.go" line_range="464" />
<code_context>
- } else {
- sendNotify(localeIconStart, "", notifyTxtStart)
- }
+ if needsInstall && networkEnabled {
+ sendNotify(localeIconStart, "", notifyTxtStartWithInstall)
+ } else {
</code_context>
<issue_to_address>
**Failed installs appear successful**
When lastore rejects the install request or reports a failed package job, `installLangSupportPackages` returns an error, but `setLocale` only logs it before sending the finished notification and marking the locale change complete. Users see success while the support packages remain absent.
Propagate the installation error so `setLocale` does not report the locale change as successfully completed.
</issue_to_address>
deepin pr auto review🤖 AI 代码审查报告📊 总体评价
🔍 详细分析1. 语法逻辑 ❌评价: 需改进 ❌ 不通过 潜在问题:
建议: 在 getInstallLangSupportPackages() 函数中使用 defer ls.Destroy() 确保资源释放,或恢复原来的显式 Destroy 调用 2. 代码质量 ✅评价: 优秀 ✅ 通过 潜在问题: 建议: 代码质量良好,变量命名从 isInstalled 改为 needsInstall 更准确,installLangSupportPackages 复用 getInstallLangSupportPackages 消除了重复代码 3. 代码性能 ✅评价: 优秀 ✅ 通过 潜在问题: 建议: 性能良好,使用 SystemBus 访问 NetworkManager 更合理,网络状态检查 state==70(NM_STATE_CONNECTED_GLOBAL) 更精确 4. 代码安全 🔒评价: 优秀 ✅ 通过
安全漏洞详情: 建议: 无安全漏洞,代码安全合规 💡 改进建议代码示例func (lang *LangSelector) getInstallLangSupportPackages(locale string) ([]string, error) {
ls, err := language_support.NewLanguageSupport()
if err != nil {
return nil, dbusutil.ToError(err)
}
defer ls.Destroy() // 确保资源释放
return ls.ByLocale(locale, false), nil
}本报告由 AI 代码审查工具自动生成 |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: fly602, mhduiy The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
…and Sourcery markers B7: Gemini and Qodo have no verified producing check. Their apps grant `checks: read` only and no published CheckRun or StatusContext was found in the live search. The Gemini push-re-review default is also UNVERIFIED here (Google's docs describe the initial review and a manual `/gemini review` trigger, not an automatic new-push re-review), so the only confirmed shape is comment-only. Greptile and Sourcery checks ARE verified: - Greptile: b-editor/beutl#3095 prints `{"name":"Greptile Review","app_slug":"greptile-apps"}`. - Sourcery: linuxdeepin/dde-daemon#1280 prints `{"name":"Sourcery review","app_slug":"sourcery-ai"}`. DEFAULT_CHECK_MARKERS now carries only verified producers. The Kilo marker covers the historical `kilocode` and the current `kilo-code-bot` app slugs (renamed 2025-10-28). Login-side identity sets for Gemini and Qodo are unchanged: a future vendor that publishes a check must add a marker with evidence, not borrow one. Tests: - `test_issue_82_new_check_markers_route_to_their_reviewer` now exercises only the verified Greptile and Sourcery markers. - New `test_issue_82_gemini_and_qodo_check_markers_are_not_added` pins the absence: a check naming Gemini or Qodo does not auto-route.
…mary evidence (#119) * [Issues #82 #117] widen external-reviewer identities and add Kilo summary evidence Issues #82 and #117, one lane: - inspect_external_reviews.py: add gemini-code-assist, greptile, sourcery, qodo to DEFAULT_IDENTITIES with verified DEFAULT_CHECK_MARKERS. github-actions[bot] stays out: shared by every workflow, not a stable identity. Kilo summary evidence path: a <!-- kilo-review --> PR issue comment from a trusted Kilo identity counts as head review evidence when the comment's createdAt is at or after the Kilo check's startedAt (chronological proxy for "after the head push") or the Kilo check has a completedAt (the safety valve, the PR #114 shape). "No Issues Found" puts Kilo in completed_on_head; any other status surfaces the summary as a current-head finding for the existing disposition path. A failed Kilo check whose description names the rate-limit phrase gets a distinct pending reason (not the generic 'trusted review check failed' error) so the #48 rate-limit breakpoint can count it across all built-in reviewers. - 4 new fixtures under tests/fixtures/external_reviews/: kilo-summary- clear-at-head, kilo-summary-stale, kilo-summary-with-issues, kilo-rate-limited-failed-check. - tests/test_external_review_inspector.py: 14 new tests pin each new login/marker, the kilo-review ordering rule, the four fixture cases, the github-actions[bot] exclusion, the ask-once surface, and the #48 rate-limit breakpoint against a newly added reviewer (greptile). - phases/external-review.md: list the new reviewers with comment-only / re-review notes; document the Kilo summary evidence path; add the ask-once rule and forbid re-asking a recorded login. - PROJECT_CONTEXT_TEMPLATE.md: add Pending reviewer decisions line. - PROJECT_CONTEXT.md External Review Policy only: kilo required, coderabbit ignored, Kilo trigger rules (PR opened, new commits pushed, PR reopened, draft marked ready) replace the coderabbit-only auto-request paragraph; closing sentence updated. - CHANGELOG.custom.md: bullet under Unreleased (v2.1.2) noting the behavior change, the ask-once contract, the Kilo summary evidence path, and the new fixtures. Refs: #82, #117, #48 * [#82] remove unsupported Gemini and Qodo check markers; add Greptile and Sourcery markers B7: Gemini and Qodo have no verified producing check. Their apps grant `checks: read` only and no published CheckRun or StatusContext was found in the live search. The Gemini push-re-review default is also UNVERIFIED here (Google's docs describe the initial review and a manual `/gemini review` trigger, not an automatic new-push re-review), so the only confirmed shape is comment-only. Greptile and Sourcery checks ARE verified: - Greptile: b-editor/beutl#3095 prints `{"name":"Greptile Review","app_slug":"greptile-apps"}`. - Sourcery: linuxdeepin/dde-daemon#1280 prints `{"name":"Sourcery review","app_slug":"sourcery-ai"}`. DEFAULT_CHECK_MARKERS now carries only verified producers. The Kilo marker covers the historical `kilocode` and the current `kilo-code-bot` app slugs (renamed 2025-10-28). Login-side identity sets for Gemini and Qodo are unchanged: a future vendor that publishes a check must add a marker with evidence, not borrow one. Tests: - `test_issue_82_new_check_markers_route_to_their_reviewer` now exercises only the verified Greptile and Sourcery markers. - New `test_issue_82_gemini_and_qodo_check_markers_are_not_added` pins the absence: a check naming Gemini or Qodo does not auto-route. * [#117] rebuild rate-limit fixture from real failed Kilo run; fetch check output via REST B4: the rate-limit phrase lives in the head SHA's check run `output.summary`, but `gh pr view --json statusCheckRollup` returns a CheckRun shape that omits both `output` and the run id. The previous fixture invented a `description` field and the "Will retry on the next push" suffix; live data had neither. - New `fetch_check_output` calls `repos/{owner}/{repo}/commits/{head_sha}/check-runs` for the named check and returns the most recent run's `output` (plus the canonical timing/app fields the rollup sometimes omits). - `augment_checks_with_output` is called from `main` after the live `fetch_pr`. It only fills a check that lacks both `output` and `description`, so fixtures that deliberately model an absent output stay authoritative. - `check_description` now reads `output.summary`, `output.title`, and `output.text`, in that order, plus the legacy `description`. - Fixture `kilo-rate-limited-failed-check.json` is rebuilt from the real failed run on PR #114 (check run 115580659602, head 91e1cb4): timing 22:48:19Z–22:59:16Z, app slug `kilo-code-bot` (not the historical `kilocode`), and `output: { title: "Kilo Code Review failed", summary: "Review failed: Assistant request was rate limited" }`. The invented "description" and the "Will retry on the next push" suffix are gone. The inspector now reads the rate-limit phrase from a real field, and a future vendor that names its failure mode differently in `output.title` is caught too. * [#117] bind Kilo summary to head's successful run; enforce Status+Recommendation; route summary findings through disposition B1: the previous ordering rule admitted any non-empty `completedAt`, so a year-old completed Kilo run cleared against a fresh head. The new rule is: 1. The Kilo check for the head SHA COMPLETED with `conclusion == "success"` (case-folded). A failed, still-running, or non-success run is not a head review. 2. The summary comment's `updatedAt` (or `createdAt` when the comment was never edited) parses as ISO 8601 AND is at or after the run's `startedAt`. A malformed date fails closed rather than silently satisfying the compare. The `parse_iso8601` helper gates the timestamp; a date that fails to parse becomes `None` and the comment is treated as not bound to this run. The B1 negative test exercises a year-old summary paired with a newly-completed SUCCESS run; the inspector stays `pending` and Kilo is not in `completed_on_head`. The malformed-timestamp probe (`createdAt = "zzzz"`) likewise stays `pending`. B2: the previous implementation parsed only the `Status` field. `kilo_summary_fields` now returns `(status, recommendation)`, and the clear rule requires BOTH `Status: No Issues Found` AND `Recommendation: Merge`. Issue #117's scope comment is explicit on this. A `Status: No Issues Found | Recommendation: Request Changes` summary is surfaced as a current-head finding the lead triages. B3: the summary helper now accepts the disposition map and sets `disposition` on the finding it returns. A `blocking` disposition routes the gate to `blocking` exactly like a triaged review-thread finding; an `advisory` or `false_positive` disposition releases the seat the way other reviewers' findings do. The hard-coded `None` is gone. Kilo checks handled by the summary path are returned in a new `consumed_check_ids` set, and the main `inspect()` skips them in the generic `check_failed` path. Without this, a failed Kilo check would add both a specific rate-limit (or non-success) pending reason AND the generic "trusted review check failed without readable current-head findings" error, routing the gate to `incomplete` instead of `pending`. Tests added: `test_issue_117_kilo_summary_edited_in_place` (PR #118 shape), `test_issue_117_old_summary_with_completed_head_check_does_not_clear` (B1 negative), `test_issue_117_failed_check_does_not_clear_summary` (all non-success conclusions), `test_issue_117_malformed_timestamp_does_not_clear` (B1 timestamp probe), `test_issue_117_no_issues_found_with_request_changes_does_not_clear` (B2), `test_issue_117_summary_finding_can_be_dispositioned_as_blocking` (B3, all three dispositions). * [#82 #48] rate-limited reviewers stay pending even when a review completed B5: a current-head Greptile COMMENTED review plus a failed rate-limited Greptile check was routing the gate to `clear`. The review evidence was correctly recorded in `completed_on_head`, but `pending_reviewers` did not include the rate-limited reviewer, so the gate cleared. The rate-limit is a separate signal that the lead's retry or breakpoint path must see. `pending_reviewers` now unions `rate_limited_reviewers` for every reviewer, not just Kilo. A Greptile (or any built-in reviewer) with a completed review AND a rate-limited check ends up in both `completed_on_head` and `pending_reviewers`, with the rate-limit reason in `pending_reasons`. The state is `pending` (not `clear`) because the rate-limit requires a lead decision. Test `test_issue_82_b5_rate_limited_reviewer_with_completed_review_is_pending` probes the Greptile case from the B5 review. `completed_on_head` is still `["greptile"]` so the lead's audit trail sees both signals; `pending_reviewers` is `["greptile"]` with a rate-limit reason and zero errors. * [#82 #117] M3: rate-limit only on FAILED checks; B1 doc; PR #118 fixture; app.slug fidelity M3 (QA round 1): `is_rate_limited_check` returned True for any check whose text payload mentioned a rate-limit, even SUCCESS checks. A SUCCESS Kilo check whose description said "previous attempt was rate limited; this run retried" was misclassified as a rate-limit failure, discarding a legitimate clear verdict (QA probe s8). `is_rate_limited_check` now requires the check to be FAILED (non-success conclusion, or status=failure/error) AND its text payload to name the rate-limit phrase. A SUCCESS check that merely *mentions* a past rate-limit is not a rate-limit failure — vendor retry history is not actionable infrastructure evidence. A new `is_failed_check` helper carries the conclusion/status check; the `KILO_RATE_LIMIT_PHRASE` clause is now structurally redundant (a substring of `RATE_LIMIT_PHRASE`) and is documented as such rather than removed, so the constants stay load-bearing as named references in logs and tests. B1 documentation: `external-review.md` previously documented the rule as "the comment's `createdAt` is at or after the Kilo check's `startedAt`". PR #118's real data shows that `createdAt` is stale on every re-review (created 00:03:43Z against a run that started 00:22:51Z), so the documented branch would fail on the real #118 shape. The rule is now documented as the comment's `updatedAt` (falling back to `createdAt` when never edited) at or after the run's `startedAt`, with both dates required to parse as ISO 8601 so a malformed value fails closed. PR #118 fixture: `kilo-summary-edited-in-place.json` captures the real shape: `createdAt` 00:03:43Z, `updatedAt` 00:26:26Z, head run started 00:22:51Z completed 00:26:24Z, conclusion SUCCESS, comment No Issues Found + Merge. The fixture clears via the edited-in-place path, proving the B1 binding rule against the real re-review data. App-slug fidelity: all four Kilo fixtures previously asserted `app.slug = "kilocode"` (or `kilo-code-bot`) but live `gh pr view --json statusCheckRollup` returns `app: null` for Kilo checks. The fixtures now mirror the real shape; the inspector matches on the check's `name` ("Kilo Code Review" contains the `kilo code` marker), so the change is structural and the live data path is unchanged. Tests: - `test_issue_82_m3_success_check_mentioning_rate_limit_clears` pins the s8 fix. - `test_issue_82_m3_failed_check_with_rate_limit_is_rate_limited` pins the positive direction. - `test_issue_82_m3_unrelated_check_mentioning_rate_limit_does_not_route` pins the s7 case (a github-actions check with rate-limit text in output is not a rate-limit signal). - `test_issue_117_kilo_summary_edited_in_place_fixture_clears` exercises the new PR #118 fixture end-to-end. * [#82] B6 widened: pin Pending reviewer decisions in template and PROJECT_CONTEXT; CHANGELOG trim QA round 1 (M1): the ask-once contract was pinned only in `phases/external-review.md`. Mutations M4 (delete the line in the template) and M5 (delete the line in the root `PROJECT_CONTEXT.md`) passed both the validator and the full unit suite. This commit widens the B6 pin to all three recording sites: - `scripts/validate_skill.py`: new per-file policy for `templates/PROJECT_CONTEXT_TEMPLATE.md` (carries the `Pending reviewer decisions` line and the External Review Policy structural tokens). - `scripts/validate_skill.py`: a new check on the root `PROJECT_CONTEXT.md` that fails closed when the External Review Policy does not include `**Pending reviewer decisions**`. The check runs before the routing-section check so a missing line surfaces as a distinct error. QA round 1 (M1 widening): the mutation test `test_ask_once_mutation_each_outcome_fails_validation` performs seven mutations, each in a scratch copy of the worktree so the mutation stays out of the live tree: 1. delete the entire `### Ask once` section; 2. delete the trust outcome line; 3. delete the ignore outcome line; 4. delete the decide-later outcome line; 5. delete the not-re-asked paragraph; 6. delete the `Pending reviewer decisions` line in the template; 7. delete the `Pending reviewer decisions` line in `PROJECT_CONTEXT.md`. All seven must fail the validator. A negative control (additive unrelated change) must NOT fail, proving the assertions are scoped to the ask-once contract rather than to the file in general. The test now copies the validator script into the scratch dir so the validator's `repo_root` is the scratch root and the `PROJECT_CONTEXT.md` check is exercised against the mutated copy. CHANGELOG: the `Unreleased (v2.1.2)` Added section is trimmed to ~25 lines (was ~75) and the Changed section corrects the prior overclaim that the template carries the new policy values — the template keeps its generic defaults and gains only the new `Pending reviewer decisions` line. * [#82 #117] N1: GET method for REST fetches; N3: fix docstring; A1: dead code; QA-N1: latest Kilo run + consume all; A3: datetime parse; B3: summary IS completion Round 3 blocking items. Six commits worth of changes, one per item group, bundled here where the changes are tightly coupled. N1: `fetch_check_output` and the new batch `fetch_check_outputs_for_head` now use `--method GET` with `check_name` and `filter=all` encoded into the URL's query string. `gh api` defaults to POST whenever request parameters are supplied (via `-f`/`-F`), and a POST to the check-runs endpoint would silently create or mutate a check run on the head SHA. A transport-contract test asserts the exact argv: `--method GET` is present, `-f`/`-F` are absent, and the URL carries `check_name=...&filter=all`. Both the single-check and batch paths are tested. N1 (error propagation): a failed REST call no longer silently falls through to the rollup's `description` (which is `null` on live Kilo checks). Instead, the caller keeps the check not-clear with a named reason; the inspector's `check_failed` path reports "trusted review check failed without readable current-head findings" for the affected reviewer. This matches the lead's instruction to not swallow the error silently. QA-N1 (latest Kilo run): `kilo_summary_evidence_for_head` now gathers ALL Kilo runs on the head SHA, sorts by `started_at` DESC with `id` DESC as a deterministic tie-break, and picks the LATEST. All Kilo runs are marked as consumed so an older failed run does not fall through to the generic `check_failed` path and produce a self-contradictory `incomplete`. The REST listing now passes `filter=all` (the default `filter=latest` hides older runs). Three new tests cover both orders (SUCCESS-then-FAILED, FAILED-then-SUCCESS) and the consume-all invariant. B3 (summary IS review completion): a bound successful Kilo summary now counts in `completed_on_head` REGARDLESS of what findings it carries. Findings gate via the normal disposition path: blocking -> `blocking`; advisory or false_positive on every finding -> `clear` when nothing else is open; untriaged -> `pending`. The `kilo-summary-with-issues` and `no_issues_found_with_request_changes` tests are updated to the new verdicts (they previously pinned the wrong outcome). A3 (timestamp parsing): `parse_iso8601` now delegates to `datetime.fromisoformat` with a trailing-`Z` normalization and returns a UTC `datetime` (not a string). Impossible calendar values like `2026-99-99T99:99:99Z` and the original `zzzz` case are rejected. Ordering comparisons are now instant comparisons, not lexical string compares. A1 (dead code): `KILO_RATE_LIMIT_PHRASE` and `kilo_summary_status` have no runtime or test readers and are deleted. The `is_rate_limited_check` docstring is updated to drop the now-nonexistent constant reference. N3 (docstring): the `check_description` docstring referenced `fetch_pr_with_check_output`, which does not exist. The actual name is `fetch_check_output`. Fixed. A1 (N+1 REST calls): `augment_checks_with_output` now fetches the head's check runs ONCE per PR (filter=all) via `fetch_check_outputs_for_head`, not once per rollup entry. A REST failure yields an empty mapping so the caller falls back to the rollup's `description` field. * [#117] N2: fetch updatedAt over REST for Kilo summary binding The Kilo summary path consumes `updatedAt` to bind an edited-in-place summary to the head's run (PR #118: created 00:03:43Z, updated 00:26:26Z, run started 00:22:51Z). The `gh pr view --json comments` shape returns `createdAt` but NOT `updatedAt`, so a real edited-in-place summary (the shape Kilo produces on every re-review) could not be bound and the inspector reported `pending` where it should have reported `clear`. Codex round 2 N2 confirmed this is a P1 integration regression. New `fetch_pr_comments_with_metadata` fetches the REST `GET repos/{owner}/{repo}/issues/{pr}/comments` endpoint (--paginate) and returns a mapping keyed by both the comment's `id` and its `node_id`, so the caller can match a `gh pr view` comment by either identifier. The transport uses `--method GET` with the URL-encoded path (no `-f`/`-F`, so `gh api` does not switch to POST). New `augment_comments_with_metadata` merges REST `created_at`/`updated_at` into the gh-shaped comments in place, with a `_restMeta` provenance block that records the source URL and the values. REST values take precedence; a missing REST value falls back to the gh `createdAt`. On REST failure the gh values remain (which fail closed for the edited case, matching the B1 invariant). Wired into the live path in `main()` after `augment_checks_with_output`. Three new tests: - `test_issue_82_n2_fetch_path_supplies_updated_at` asserts the fetch path returns both `createdAt` and `updatedAt` keyed by id and node_id, and that the transport uses `--method GET` with `--paginate` against the `issues/118/comments` endpoint. - `test_issue_82_n2_augment_merges_metadata_into_comments` asserts the merge and the `_restMeta` provenance block. - `test_issue_82_n2_fallback_when_rest_fails` asserts that a REST failure leaves the gh values intact and no provenance block is written. Live proof (quoted in the report-back): - `--repo KHAEntertainment/showrunner --pr 118 --required-reviewer kilo --ignored-reviewer coderabbit` returns `state: clear`, `completed_on_head: ["kilo"]`. - Same command with `--pr 114` returns `state: clear`, `completed_on_head: ["kilo"]`. * [#82 #117] Round 3 coverage pins + A2 rewrite (no suite recursion) Incident note: the first round-3 attempt at coverage-pin tests shipped an in-suite mutation harness that invoked `python -m unittest discover` from inside the test suite. Each child re-discovered the same file and spawned more, putting 200+ Python processes on a shared host. That harness is DROPPED. This commit re-ships the same coverage guarantees with a strictly bounded shape: - Coverage pins (QA M6, M7, M8) are pure TEXT ASSERTIONS. No subprocess, no discovery, no side effects. They read the shipped file and assert tokens: - M6: the four new Known-identities bullets in `phases/external-review.md` (Gemini, Greptile, Sourcery, Qodo) plus the `github-actions[bot]` non-addition; - M8: the root `PROJECT_CONTEXT.md` External Review Policy values (`Required reviewers: kilo`, `Ignored reviewers: coderabbit`); - M7: the `CHANGELOG.custom.md` `Unreleased (v2.1.2)` entry tokens (four new reviewers, Ask-once contract, Kilo summary evidence, kilo required, coderabbit ignored). - The validator's own pin for the root `PROJECT_CONTEXT.md` `Pending reviewer decisions` line is tightened to require the full `**: none` form (a bare `**Pending reviewer decisions**` substring was previously enough, so a mutation that rewrote `: none` to `: removed for QA` passed). The stricter check fails closed on any edit that drops or rewords the line. - A2 (the B6 mutation test) is REWRITTEN: - each of the 7 cases starts from a PRISTINE copy of the Skill in a fresh `tempfile.TemporaryDirectory` (no cumulative state across mutations); - each mutation is a REAL line/section DELETION, not a substring replacement that leaves the validator's key intact; - the additive-control probe is applied to `CHANGELOG.custom.md` (which has no routing-section check) rather than to the mutated target, so the control cannot accidentally trip the validator's `PROJECT_CONTEXT.md` `## Execution Routing Policy` whole-section-equality check; - the test ONLY invokes `scripts/validate_skill.py` on the temp copy (the one mutation-proof mechanism the rules permit inside the suite). It never runs the test suite (`unittest discover`, `verify.sh`, `pytest`), so there is no recursion and no process fan-out. Outside-the-suite mutation proof (validator + single-module `tests.test_backend_contract`) runs ONE mutation at a time from a scratch clone, per the lead's hard rules. * [#117] rate-limit fixture: add run id 115580659602 + filter=all provenance The lead verified with `gh api .../check-runs?filter=all` that run 115580659602 on commit 91e1cb4 is a real Kilo failure (22:48:19-22:59:16Z, `output.summary: "Review failed: Assistant request was rate limited"`). The default `filter=latest` hides this older run; the LATEST run on that SHA is the success 115591827668 (23:20:05-23:25:48). The fixture now carries a `_provenance` block with: - `run_id: 115580659602` - `filter: "all"` - `fetch_command`: the exact gh api invocation - a note explaining the filter=all requirement and the second (success) run on the same SHA The fixture's shape is unchanged; the inspector still reads `output.summary` and produces the same `pending` + distinct rate-limit reason. The provenance is metadata only. * [#82 #117] make CHANGELOG check tolerant of absence (fixture trees) The round-3 gate run failed on 22 tests in `tests/test_validate_skill.py` (`ERROR: missing required file: CHANGELOG.custom.md`). The fixture tree those tests build copies `skills/dev`, `scripts/validate_skill.py`, and `PROJECT_CONTEXT.md` but NOT `CHANGELOG.custom.md`, so the new M7 coverage pin's "missing required file" check rejected every fixture run. Fix: the CHANGELOG check is now CONDITIONAL on the file existing, matching the same tolerance pattern the validator already uses for `EXTRA_MARKDOWN_DIRS` (`en/`, `zh/`) and for the root `*.md` home-path scan. A fixture or archival tree that does not carry the CHANGELOG is not a defect; the check applies only when the file is present, which is the shape a real source tree has. The M7 mutation (deleting the `## Unreleased (v2.1.2)` section from the CHANGELOG) is still caught, because the file remains present with the section missing. The check for `**Pending reviewer decisions**: none` in `PROJECT_CONTEXT.md` is unchanged and still required, because the fixture DOES copy that file. Verified after the fix (single-module runs only, no discover): - `python3 scripts/validate_skill.py` -> 0 - `python3 -m unittest tests.test_validate_skill` -> 27 OK - `python3 -m unittest tests.test_backend_contract` -> 102 OK - `python3 -m unittest tests.test_external_review_inspector` -> 100 OK * [#82 #117] Bind summary and check-run evidence to one record; release-aware changelog pin F1 (Codex round-3, blocking/Critical): REST edit metadata promoted an old summary body to current-head evidence. The first gh read supplied the comment body; the later REST read supplied newer edit timestamps but DISCARDED the REST body. If Kilo edited the comment in place between the two reads, the inspector bound the OLD body to the NEW edit time — the exact in-place edit behavior that motivated N2. Fix: `fetch_pr_comments_with_metadata` now returns the REST record's `body` alongside `created_at`/`updated_at`. `augment_comments_with_metadata` replaces the comment's body, createdAt, and updatedAt ALL from the same REST record — one consistent comment version. If the REST record is incomplete (missing body or missing timestamps), the comment is marked `_incoherent: True` and the inspector treats it as not evidence (pending), never clear. A fresh timestamp must never license stale text. F2 (Codex round-3, blocking): field-filling mixed the REST latest run's id/output with the older gh SUCCESS conclusion and times. If a new run appeared between the gh read and the REST read, the merged record claimed the newer run's ID and output but the older run's SUCCESS conclusion and start/completion times. Fix: `augment_checks_with_output` now uses the selected latest REST run as ONE WHOLE record — id, status, conclusion, started/completed, and output all from that run. No field-by-field merging with gh rollup data for the same check. The gh rollup and REST disagree only when a new run was created between reads; the REST record is the one that describes the head SHA's latest run and wins outright. D1 (debt, per round-3): the M7 pin required the literal `## Unreleased (v2.1.2)`, so a release rename to `## v2.1.2 (YYYY-MM-DD)` broke both the validator and the backend coverage test. Both now accept either heading form (regex: `## (?:Unreleased \(v2\.1\.2\)|v2\.1\.2(? : \(\d{4}-\d{2}-\d{2}\))?)`). The same 8 #82/#117 tokens are still required inside whichever heading is present. Verified by hand in a scratch copy: rename to `## v2.1.2 (2026-10-19)` → validator 0, tests 0; delete the section → validator 1, tests 1. Two in-process regression tests (no subprocess, no suite launch): - `test_f1_rest_edit_metadata_promotes_coherent_body_only` reproduces the gh-read-then-REST-read race and asserts the verdict is `pending` + 1 untriaged (the REST body is the Issues Found one), not `clear`. - `test_f1_incomplete_rest_record_marks_comment_not_evidence` covers the unpairable case (REST record with `body: null`) and asserts the comment is marked incoherent and the inspector keeps the gate `pending`. - `test_f2_rest_run_used_as_one_whole_record` reproduces the gh-SUCCESS-then-REST-FAILURE race and asserts the merged record is the REST record entirely (id 300, conclusion failure, started 23:30:00, completed 23:35:00, output summary with rate-limit) and the verdict is `pending` with the rate-limit reason, not `clear`. Existing `test_issue_82_n2_augment_merges_metadata_into_comments` updated to include `body` in its REST record (F1 pairing requirement). Codex round-3 repro probes (before → after): - F1 `REST has new issues body, production enrichment keeps old clear body`: clear → pending (1 untriaged) - F2 `new failure output/id mixed with older SUCCESS fields`: clear → pending (rate-limit reason) - Coherent controls unchanged: year-old/absent summary stays pending; current summary clears. Light local checks (one at a time, nice -n 10): - `tests.test_external_review_inspector`: 103 OK - `tests.test_backend_contract`: 102 OK - `tests.test_validate_skill`: 27 OK - `python3 scripts/validate_skill.py`: OK Live: `--pr 118` and `--pr 114` both `state: clear`, `completed_on_head: ["kilo"]`.
问题
PMS: BUG-379697、BUG-379687、BUG-379685
控制中心切换系统语言后,locale 正常生成、界面语言正常切换,但本应自动安装的语言支持包(字体、拼写词典、应用语言包等)从不安装,
org.deepin.dde.Lastore1收不到InstallPackage;开始时的通知也不会出现"安装"那一条。另外GetLanguageSupportPackages查询很慢,可能超过调用方超时。原因
getInstallLangSupportPackages()调用ByLocale(locale, false),false表示只返回尚未安装的包,但setLocale()却写成isInstalled := len(pkg) != 0,于是有包要装时被当成"已安装"而跳过,没有缺包时才进入安装流程(装一个空列表)。isNetworkEnable()读取会话总线org.deepin.dde.Network1的State,而 dde-network-core 2.0 中该对象是兼容层,State固定返回0,因此即使已联网也判定为断网,进一步挡住安装。language_support对每个候选包各启动一次dpkg-query/apt-cache policy;apt-cache每次启动都要加载整个包缓存并计算 pin,候选包有几十个时耗时累积到数十秒。修改
langselector1/locale.go:needsInstall := len(pkg) != 0,有缺包且联网才安装。isNetworkEnable()改为读取系统总线上org.freedesktop.NetworkManager的State属性(经go-dbus-factory的 system 绑定),不再依赖会话org.deepin.dde.Network1兼容层。NM_STATE_CONNECTED_GLOBAL (70):仅本地/站点连通无法访问软件源。installLangSupportPackages()复用getInstallLangSupportPackages(),避免重复查询。查询侧的批量改造在 dde-api:linuxdeepin/dde-api#205。
验证
go test ./langselector1通过。setLocale()的四种组合(联网/断网 × 有缺包/无缺包):只有"联网且缺包"会发起安装,断网仍能正常完成语言切换。State返回70,修改后的读取函数判定为已连接;0~60判定为未连通。dde-api的批量查询修复(linuxdeepin/dde-api#205)需一并合入,否则查询仍会逐包起进程;打包时 dde-daemon 依赖已安装的dde-api-dev源码,需要先更新 dde-api。