refactor(ci): port the stable wrapper E2E to Rust and drop its PowerShell call point (#78) - #80
Conversation
|
Caution The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased. |
|
Warning Review limit reached
Next review available in: 42 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
📝 WalkthroughSummary by CodeRabbit
WalkthroughThe legacy PowerShell stable-wrapper E2E test was deleted. CI no longer runs or parser-checks it. Rust integration tests now cover successful and failed wrapper runs, artifact publication, manifest resolution, and authoritative indexing. ChangesStable wrapper E2E coverage
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
crates/code-intel-cli/tests/stable_wrapper_e2e.rs (4)
156-159: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAssert the outcome on one line instead of two independent substrings.
outputis the concatenation of stdout and stderr. The current check passes whenOutcome:andcompletedappear anywhere in that text, including on different lines. The tokencompletedis common in run identities, node status text, and log lines. The assertion can therefore pass while the summary printsOutcome: process_failed.The PR keeps this test specifically to cover the summary lines that
main.rsprints. Matching a single line preserves that guarantee.♻️ Proposed line-scoped assertion
- assert!( - output.contains("Outcome:") && output.contains("completed"), - "summary lacks the completed outcome: {output}" - ); + assert!( + output + .lines() + .any(|line| line.contains("Outcome:") && line.contains("completed")), + "summary lacks the completed outcome: {output}" + );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/code-intel-cli/tests/stable_wrapper_e2e.rs` around lines 156 - 159, Update the assertion in the stable-wrapper end-to-end test to match a single complete output line containing both the “Outcome:” label and “completed,” rather than checking independent substrings across output. Preserve the test’s coverage of the summary emitted by main.rs and avoid matches from unrelated run identities, statuses, or log lines.
89-92: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueAdd context to the marker unwrap.
The doc comment states that this helper exists so the test fails when the marker stops binding the manifest. If
manifest.pathis missing or is not a string,unwrap()panics with a generic message and does not show the marker contents. Every other fallible step in this file usesunwrap_or_elsewith a descriptive panic. Matching that pattern makes the guarded contract self-reporting.♻️ Proposed diagnostic message
fn manifest_of(run: &Path) -> Value { let marker = read_json(&run.join("run-complete.json")); - read_json(&run.join(marker["manifest"]["path"].as_str().unwrap())) + let relative = marker["manifest"]["path"] + .as_str() + .unwrap_or_else(|| panic!("marker does not bind a manifest path: {marker}")); + read_json(&run.join(relative)) }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/code-intel-cli/tests/stable_wrapper_e2e.rs` around lines 89 - 92, Update manifest_of so the manifest.path extraction uses unwrap_or_else with a descriptive panic that includes the marker value, while preserving the existing read_json flow. Match the file’s established fallible-step diagnostic pattern and ensure missing or non-string paths report the marker contents.
31-43: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider isolating the
gitinvocations from developer global configuration.The commit invocations set
user.nameanduser.emailinline, so identity is safe. Global configuration can still break the fixture. If a developer setscommit.gpgsign=trueglobally, the fixture commit fails and the test reports agiterror instead of a wrapper defect. A hook template frominit.templateDircan also run duringgit init.Setting the environment once in the helper keeps every call hermetic.
♻️ Proposed hermetic git helper
fn git(repo: &Path, args: &[&str]) { let output = Command::new("git") .arg("-C") .arg(repo) + .env("GIT_CONFIG_GLOBAL", "/dev/null") + .env("GIT_CONFIG_SYSTEM", "/dev/null") + .env("GIT_CONFIG_NOSYSTEM", "1") .args(args) .output() .unwrap_or_else(|error| panic!("git {args:?} could not start: {error}"));Note that
/dev/nullis not portable to Windows; useNULthere, or point both variables at a file inside the fixture root.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/code-intel-cli/tests/stable_wrapper_e2e.rs` around lines 31 - 43, Update the git helper to isolate all Git invocations from developer configuration by setting the appropriate environment variables once, including disabling global config, commit signing, and hook templates. Use a portable null-device value or fixture-local file instead of hardcoding /dev/null, while preserving the existing command execution and failure reporting.
244-249: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winPin the process-failure exit code.
assert_ne!(code, Some(0))only rejects success; it still passes when the child receives a signal (codeisNone). This invalid UTF-8 fixture already expectsprocess_failed, anddag_coordinator.rsreturns exit code70forProcessFailedandIncomplete. AssertSome(70)to cover the documentedrun executeprocess-failure exit-code contract.♻️ Proposed exit-code assertion
- assert_ne!( - code, - Some(0), - "wrapper hid an authoritative failure: {output}" - ); + assert_eq!( + code, + Some(70), + "wrapper did not report the documented process-failure exit code: {output}" + );🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/code-intel-cli/tests/stable_wrapper_e2e.rs` around lines 244 - 249, Update the exit-code assertion in the run_wrapper test to require Some(70) rather than merely rejecting Some(0), preserving the existing output message and validating the documented ProcessFailed/Incomplete exit-code contract.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/code-intel-cli/tests/stable_wrapper_e2e.rs`:
- Around line 66-78: Update latest_core_run to identify the newest run by its
runIdentity marker or manifest before selecting its -core directory, rather than
relying on lexicographic sorting and runs.pop(). Account for commit() placing
final_name directly under the authority directory, and exclude completed_run if
that is the established non-run directory.
---
Nitpick comments:
In `@crates/code-intel-cli/tests/stable_wrapper_e2e.rs`:
- Around line 156-159: Update the assertion in the stable-wrapper end-to-end
test to match a single complete output line containing both the “Outcome:” label
and “completed,” rather than checking independent substrings across output.
Preserve the test’s coverage of the summary emitted by main.rs and avoid matches
from unrelated run identities, statuses, or log lines.
- Around line 89-92: Update manifest_of so the manifest.path extraction uses
unwrap_or_else with a descriptive panic that includes the marker value, while
preserving the existing read_json flow. Match the file’s established
fallible-step diagnostic pattern and ensure missing or non-string paths report
the marker contents.
- Around line 31-43: Update the git helper to isolate all Git invocations from
developer configuration by setting the appropriate environment variables once,
including disabling global config, commit signing, and hook templates. Use a
portable null-device value or fixture-local file instead of hardcoding
/dev/null, while preserving the existing command execution and failure
reporting.
- Around line 244-249: Update the exit-code assertion in the run_wrapper test to
require Some(70) rather than merely rejecting Some(0), preserving the existing
output message and validating the documented ProcessFailed/Incomplete exit-code
contract.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: afa14ee1-7303-4b0b-8fe3-e4b9481b1c82
📒 Files selected for processing (4)
.github/workflows/ci.ymlcrates/code-intel-cli/tests/stable_wrapper_e2e.rsdocs/ps1-exit/contract-inventory.mdlegacy/scripts/tests/test-stable-wrapper-e2e.ps1
💤 Files with no reviewable changes (2)
- .github/workflows/ci.yml
- legacy/scripts/tests/test-stable-wrapper-e2e.ps1
| fn latest_core_run(authority: &Path) -> PathBuf { | ||
| let mut runs: Vec<PathBuf> = fs::read_dir(authority) | ||
| .unwrap_or_else(|error| panic!("no authority at {}: {error}", authority.display())) | ||
| .filter_map(|entry| { | ||
| let path = entry.unwrap().path(); | ||
| let name = path.file_name()?.to_str()?.to_string(); | ||
| (path.is_dir() && name.ends_with("-core")).then_some(path) | ||
| }) | ||
| .collect(); | ||
| runs.sort(); | ||
| runs.pop() | ||
| .unwrap_or_else(|| panic!("no authoritative run under {}", authority.display())) | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Find how authoritative `-core` run directory names are composed.
set -euo pipefail
# Locate the publication/commit code that builds the final run name.
rg -nP --type=rust -C6 '"-core"|-core\b|final_name|FinalName' crates | head -200
# Look for the timestamp/stamp formatting used for run identities.
rg -nP --type=rust -C4 'fn .*(run_name|final_name|stamp|run_identity)' crates | head -120Repository: 2233admin/code-intel-pipeline
Length of output: 22074
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== Relevant test snippet =="
sed -n '50,90p;240,270p' crates/code-intel-cli/tests/stable_wrapper_e2e.rs
echo
echo "== latest_core_run callers and artifact helpers =="
rg -n --type=rust -C5 'latest_core_run|latest_run_dir|utc_run_stamp|final_name' crates/code-intel-cli/src | head -260
echo
echo "== RunCommitBuilder/final_name construction sites =="
rg -n --type=rust -C5 'final_name\s*:|final_name:|RunCommitBuilder|run commit' crates/code-intel-cli/src crates/code-intel-cli/tests/stable_wrapper_e2e.rs crates/code-intel-cli/tests/run_commit.rs | head -360
echo
echo "== Stable wrapper final_name passes =="
rg -n --type=rust -C8 'final_name|stable_wrapper|completed_run|failed_run|latest_core_run' crates/code-intel-cli/tests/stable_wrapper_e2e.rsRepository: 2233admin/code-intel-pipeline
Length of output: 42339
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
src = Path("crates/code-intel-cli/src/run_commit.rs").read_text()
m = re.search(r"fn commit\(.*?\n\}\n\nfn validate_final_name", src, re.S)
if not m:
print("commit function not found")
raise SystemExit(1)
body = m.group(0)
print("commit body length:", len(body))
print("uses final_name:")
print(" final_path:", "final_path = authority_root.join(final_name)" in body)
print(" rename_directory_no_replace:", "rename_directory_no_replace(&stage_path, &final_path)" in body)
print(" utc_run_stamp:" in body)
# Programmatically check whether the commit function directly consumes any timestamp/stamp helper.
print("contains utc_run_stamp call expression:", "utc_run_stamp(" in body)
print("contains utc_now() call expression:", "utc_now(" in body)
print("contains SystemTime::now() expression:", "SystemTime::now()" in body)
PYRepository: 2233admin/code-intel-pipeline
Length of output: 404
Select the latest run by run identity before picking a -core directory.
run commit moves final_name directly to the authoritative directory, so commit() does not generate the utc_run_stamp name used by latest_run_dir(). If final_name is not guaranteed chronologically monotonic, runs.pop() can return the wrong run. Select by runIdentity marker/manifest instead, or explicitly exclude completed_run.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@crates/code-intel-cli/tests/stable_wrapper_e2e.rs` around lines 66 - 78,
Update latest_core_run to identify the newest run by its runIdentity marker or
manifest before selecting its -core directory, rather than relying on
lexicographic sorting and runs.pop(). Account for commit() placing final_name
directly under the authority directory, and exclude completed_run if that is the
established non-run directory.
|
🔒 Repowise is not analyzing this repository The PR bot is free on public repositories. This one is private, which needs a Pro plan. |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/code-intel-cli/tests/primary_entry.rs`:
- Around line 128-141: The skip condition in the test around run_wrapper must
inspect the doctor failure’s diagnostic, not merely output.contains("Domain
failure: doctor"). Only return early when the output explicitly identifies a
missing host toolchain/tool diagnostic; preserve the authoritative
run/index/query assertions for doctor bootstrap, manifest/config, provider
conformance, and other domain failures.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 33a810ff-223f-4022-96fe-6a38a7623e75
📒 Files selected for processing (2)
.sentrux/baseline.jsoncrates/code-intel-cli/tests/primary_entry.rs
* fix(sentrux): coupling must not measure the PowerShell share of the tree (#78) `coupling_score` is import lines per file. The scanner reads import/from/use/mod/require(/#include/using, none of which is how PowerShell declares a dependency — it dot-sources and calls Import-Module. Counting .ps1/.psm1 in the denominator therefore made the score fall whenever PowerShell grew and rise whenever it shrank. Under the PS1 retirement campaign that inverts the gate. PR #80 deleted one PowerShell test, added the Rust test that replaces it, raised quality_signal by 60, and still failed `coupling_increased` 45.64 -> 45.73. Every one of the ~43 remaining call points would have failed the same way, so the ratchet was measuring the campaign rather than regression. Numerator and denominator now both cover only languages whose imports the scanner models. A tree with none of the unmodelled languages scores exactly as before; this one measures 74.41 (1064 edges over 143 modelled files) where dilution reported 45.48. Everything else — size, functions, complexity, god files — still covers every collected extension. Consequences, all in this commit: - baseline re-saved; schema -> code-intel-sentrux-baseline.v3, so a v2 baseline fails closed as `baseline_engine_mismatch` with the re-baseline instruction instead of reporting a fabricated ~30-point coupling regression on first run after upgrade. - max_coupling accepts a bare number as well as an A..D grade. The ladder tops out at D = 6 imports per file, which no idiomatic Rust tree stays under, so keeping "D" would mean a permanently red rule. .sentrux/rules.toml records the measured 76.0 as a ratchet; tightening is tracked with the other threshold debt in #14. - the PowerShell shim mirrors both changes, so a shim injected through options.toolPathPrefix cannot compare an old-formula score against a new-formula baseline. - [coupling_basis] and metrics.import_modeled_files report the denominator rather than leaving it to be derived from the ratio. Verified: cargo test 2633 passed / 46 suites; cargo fmt clean; retirement packet suite 8 packets + 2 audits PASS; authoritative self-scan puts diagnosis.hospital back to succeeded/pass on this tree. With #80's diff applied on top, the gate reads 74.41 -> 74.31 and passes. Refs #78 * fix(sentrux): re-pin the capability toolchain digest for sentrux_gate.rs `provider.sentrux-adapt` carries the gate source digest in two places: the internalization record and `orchestration/integrations.json`'s toolchainDigests. The first commit updated only the record, so test-atomic-capability-contract.ps1 failed on all four CI lanes with "provider.sentrux-adapt toolchain digest is stale for crates/code-intel-cli/src/sentrux_gate.rs". test-atomic-capability-contract.ps1 now passes locally; the gate still reports no degradation. Refs #78 * fix(compatibility): refreeze the six packets that pin orchestration/integrations.json E02, E03, E04, E07, E08 and E10 all carry integrations.json in their frozen source set, so re-pinning the sentrux_gate.rs toolchain digest made every one of them stale. Same mechanism the E10 verifier documents for #48's edit to the same file. Regenerated with each packet's own generator at its recorded EvaluatedAt (1785441780), so the only fields that move are snapshotIdentity, artifact ref sha256s and the request/approval digest payloads that carry them. Blockers, decisions, evidence classes, window timestamps and file sets are byte-identical — verified field by field before installing. Also removes the generators' rollback scratch under legacy/work/ — it is gitignored but not invisible to the scanner, and three copies of run-code-intel.ps1 left there pushed the tree to 242 files / 36 god files and failed the gate on quality. Refs #78
…hell call point (#78) `test-stable-wrapper-e2e.ps1` never tested PowerShell. Every assertion in it was already about the compiled binary: the default route with no subcommand, the `*-core` run it publishes, what the authoritative index does with a run that failed, and the human-facing summary lines. But no Rust test asserted those summary lines — `[PASS]`, `[FAIL]`, `Outcome:`, `Cause:`, `Run evidence:` are printed from `main.rs:470` and nothing else covered them — so dropping the step would have silently removed the only cover for the binary's own user-facing output. Ported verbatim to `tests/stable_wrapper_e2e.rs`, keeping every assertion: - a clean fixture (including an unsupported binary file, which must not be grounds for rejection) publishes a completed run whose `evidence.graph`, `evidence.sentrux` and `diagnosis.hospital` nodes all pass - the doctor observation is published and the default route's repowise skip reaches the authoritative doctor policy - the completed run becomes the single A08 entry, and a provider payload query closes on it as `current` - invalid UTF-8 in a source file yields `process_failed`, the failed run is retained for audit, the index keeps pointing at the last completed run, and the failure is classified `non_completed` in the diagnostics - an invalid repository path returns one concise line with no source location The manifest is now reached through the marker rather than by name, so the test fails if the marker ever stops binding it. This test now runs on ubuntu and macos too, where the PowerShell version never did — the campaign wants those lanes first-class (#53), so CI proving it is the point rather than a side effect. Refs #78, #47
…f host toolchain state Two follow-ups on the port, both found by CI. **Coupling.** The self-scan failed with `coupling_increased` (45.64 -> 45.67). Deleting a 198-line PowerShell file removes a low-coupling node from a repository-wide average, so the average rises. Measured both ways on this branch: with `test-stable-wrapper-e2e.ps1` restored and the same Rust changes in place, coupling moves *down* to 45.48 and the gate passes. Nothing here got more coupled. Folding the test into `tests/primary_entry.rs` instead of a new file halved the delta (45.73 -> 45.67) but could not remove it, because the cause is the deletion, not the addition. The baseline is re-saved; no threshold in `rules.toml` moved, only the comparison point. Expect this on every batch that deletes a PowerShell file — that layer has been diluting this average, and retiring it makes the remaining Rust average look worse without any code getting worse. **Host toolchain.** The test now tolerates a doctor-only domain failure the way `dag_run.rs` already does: the default route passes the doctor no flags, so on a machine missing a pinned tool the failure describes the host, not the wrapper. CI installs ripgrep and ast-grep pinned, so the assertions still run where it counts; every other failure still fails the test. Verified: `cargo test` 2632 passed / 45 suites, `cargo fmt --check` clean, retirement packet suite 8 packets + 2 audits, and a local self-scan whose hospital triage is now green (`clean snapshot`, no failing rules). Refs #78, #47
… causes The skip condition swallowed every doctor domain failure. `doctor_adapter.rs`'s `diagnosis` emits three distinct causes and only two of them describe the machine: bootstrap readiness and provider conformance. The third, manifest reconciliation, is about this repository's own orchestration manifest, so a regression there was being tolerated as if a tool were missing. The tolerance now requires the failure to name one of the two host causes, to not name manifest reconciliation, and to be the only domain failure in the run. Refs #78
cdf83c8 to
0299c98
Compare
… a speed budget `wait_record_pair` killed its two child processes after ten seconds of wall clock. That deadline exists to catch a store-lock deadlock, not to assert how fast `decision record` runs, and ten seconds is not a deadlock — it is a busy machine. The two-core Windows runner failed on it while the rest of the suite, now including the ported wrapper E2E that drives the whole pipeline twice, ran alongside it. Sixty seconds still catches a deadlock and stops reporting load as a defect. Refs #78
批次 2。切
test-stable-wrapper-e2e.ps1(ci L263)。为什么不能直接删步骤
它从来没测 PowerShell。每条断言都是关于编译出的二进制:无子命令的默认路线、发布的
*-corerun、失败 run 在权威索引里的待遇、以及打给人看的摘要行。但 Rust 侧没有覆盖那些摘要行——
[PASS]/[FAIL]/Outcome:/Cause:/Run evidence:由main.rs打印,没有任何测试断言过。直接删步骤等于静默丢掉二进制自身用户可见输出的唯一覆盖。做法
逐条搬进
tests/primary_entry.rs——主入口行为本来就是它的地盘,不新开文件:evidence.graph/evidence.sentrux/diagnosis.hospital三个节点全部 succeeded + passcurrent收口process_failed,失败 run 保留待审计,索引仍指向上一个 completed,诊断里被分类为non_completedroot_entry_rejects_a_missing_repository_with_usage_exit_code)manifest 改为经 marker 取路径而非按名字取,marker 哪天不再绑定它,测试就会红。
doctor 容忍:
doctor_adapter.rs::diagnosis发三种 cause,只有bootstrap readiness failed和provider conformance failed描述的是宿主工具,而这条路线不给 doctor 传任何 flag。第三种manifest reconciliation failed是本仓自己的 orchestration manifest 状态,绝不容忍。跳过条件要求:命中前两种之一、不含第三种、且整个 run 只有这一个 domain failure。CI 装了 pinned rg / ast-grep,断言仍在该生效的地方生效。这个测试现在也会在 ubuntu / macos 上跑,PowerShell 版本从来没有。#53 要的就是这两条 lane 一等公民。
关于 coupling
本 PR 早前一版曾因删 PS1 触发
coupling_increased而重存过 baseline。#81 把 coupling 口径改成只算 import-modelled 语言,从根上解掉了这个对立,所以那次重存已 rebase 掉——本 PR 不再改动任何.sentrux/状态。rebase 后本地闸门:[coupling_basis] 143 of 238 files in import-modelled languages,Coupling 74.41 → 74.41,No degradation detected。没切的三条(分类见 #78)
test-atomic-capability-contract.ps1—— 41 条断言校验 schema / contract 常量 / registry policy / toolchain digest,需逐条比对tests/capability_exec.rs,单开一批test-project-management-support.ps1—— 被tests/internalization_record.rs:1490当作三个 advisory 记录的local-boundary-test-sha256边界证据,删前须 re-pointcheck-hardcoded-paths.ps1—— 是 lint 工具不是测试验证
cargo test2668 passed / 45 suitescargo fmt --all -- --check干净test-retirement-packets.ps1:8 packets + 2 audits 全 PASSsentrux gate无退化同时把
test-stable-wrapper-e2e.ps1从两处 PowerShell parser 检查清单里摘掉,并更新docs/ps1-exit/contract-inventory.md的-SkipRepowise行。Refs #78, #47