open-code-review-toolkit 0.9.0__tar.gz → 0.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/.gitignore +1 -0
  2. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/PKG-INFO +34 -12
  3. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/README.md +33 -11
  4. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/_version.py +2 -2
  5. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/cli.py +19 -2
  6. open_code_review_toolkit-0.10.0/src/ocr_toolkit/common/filesystem.py +68 -0
  7. open_code_review_toolkit-0.10.0/src/ocr_toolkit/posting/comments.py +21 -0
  8. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/formatting.py +46 -396
  9. open_code_review_toolkit-0.10.0/src/ocr_toolkit/posting/result.py +25 -0
  10. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/preflight.py +10 -3
  11. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/provider_config.py +33 -0
  12. open_code_review_toolkit-0.10.0/src/ocr_toolkit/providers/local.py +164 -0
  13. open_code_review_toolkit-0.10.0/src/ocr_toolkit/providers/local_config.py +14 -0
  14. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/__init__.py +1 -0
  15. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/dlp.py +197 -0
  16. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/metadata.py +90 -0
  17. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/model.py +127 -0
  18. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/outcome.py +86 -0
  19. {open_code_review_toolkit-0.9.0/src/ocr_toolkit/posting → open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting}/result.py +2 -2
  20. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/sections.py +82 -0
  21. open_code_review_toolkit-0.9.0/src/ocr_toolkit/posting/comments.py → open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/text.py +3 -3
  22. open_code_review_toolkit-0.10.0/src/ocr_toolkit/reporting/usage.py +224 -0
  23. open_code_review_toolkit-0.10.0/src/ocr_toolkit/review_debug.py +363 -0
  24. open_code_review_toolkit-0.10.0/src/ocr_toolkit/review_progress.py +126 -0
  25. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/review_receipt.py +4 -133
  26. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/review_runner.py +498 -36
  27. open_code_review_toolkit-0.9.0/src/ocr_toolkit/common/filesystem.py +0 -19
  28. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/LICENSE +0 -0
  29. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/pyproject.toml +0 -0
  30. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/__init__.py +0 -0
  31. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/common/__init__.py +0 -0
  32. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/common/git.py +0 -0
  33. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/common/language.py +0 -0
  34. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/common/markdown.py +0 -0
  35. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/common/redaction.py +0 -0
  36. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/config_writer.py +0 -0
  37. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/configure.py +0 -0
  38. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/__init__.py +0 -0
  39. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/adapters.py +0 -0
  40. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/broker.py +0 -0
  41. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/ci_outcomes.py +0 -0
  42. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/contracts.py +0 -0
  43. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/dlp.py +0 -0
  44. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/mcp.py +0 -0
  45. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/policy.py +0 -0
  46. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/recognizers.py +0 -0
  47. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/context/store.py +0 -0
  48. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/__init__.py +0 -0
  49. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/__main__.py +0 -0
  50. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/actions.py +0 -0
  51. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/artifacts.py +0 -0
  52. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/categorize.py +0 -0
  53. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collect.py +0 -0
  54. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/__init__.py +0 -0
  55. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/graphs.py +0 -0
  56. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/orchestration.py +0 -0
  57. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/projections.py +0 -0
  58. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/registry.py +0 -0
  59. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/collectors/sources.py +0 -0
  60. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/coverage.py +0 -0
  61. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/__init__.py +0 -0
  62. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/ansible/__init__.py +0 -0
  63. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/ansible/requirements.py +0 -0
  64. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/ansible/topology.py +0 -0
  65. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/contracts.py +0 -0
  66. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/go.py +0 -0
  67. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/javascript.py +0 -0
  68. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/php.py +0 -0
  69. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/ecosystems/python.py +0 -0
  70. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/__init__.py +0 -0
  71. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/contracts.py +0 -0
  72. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/detection.py +0 -0
  73. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/providers/__init__.py +0 -0
  74. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/providers/frontend.py +0 -0
  75. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/providers/go.py +0 -0
  76. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/providers/php.py +0 -0
  77. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/providers/python.py +0 -0
  78. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/registry.py +0 -0
  79. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/schema.py +0 -0
  80. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/frameworks/templates.py +0 -0
  81. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/infrastructure.py +0 -0
  82. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/invocation.py +0 -0
  83. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/mcp.py +0 -0
  84. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/model.py +0 -0
  85. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/__init__.py +0 -0
  86. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/contracts.py +0 -0
  87. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/decisions.py +0 -0
  88. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/guidance.py +0 -0
  89. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/registry.py +0 -0
  90. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/schema.py +0 -0
  91. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/policy/scopes.py +0 -0
  92. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/project.py +0 -0
  93. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/repository.py +0 -0
  94. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/review_context.py +0 -0
  95. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/__init__.py +0 -0
  96. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/atomic.py +0 -0
  97. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/contracts.py +0 -0
  98. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/core.py +0 -0
  99. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/readback.py +0 -0
  100. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/evidence/store/values.py +0 -0
  101. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/mcp_config.py +0 -0
  102. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/ocr_result.py +0 -0
  103. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/__init__.py +0 -0
  104. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/__main__.py +0 -0
  105. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/approval.py +0 -0
  106. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/gitlab.py +0 -0
  107. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/gitlab_approval.py +0 -0
  108. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/markers.py +0 -0
  109. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/payloads.py +0 -0
  110. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/reconciliation.py +0 -0
  111. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/settings.py +0 -0
  112. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/snapshot.py +0 -0
  113. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/suggestions.py +0 -0
  114. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/transaction.py +0 -0
  115. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/posting/workflow.py +0 -0
  116. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/pre_execution.py +0 -0
  117. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/provider_failure.py +0 -0
  118. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/__init__.py +0 -0
  119. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab.py +0 -0
  120. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab_ci.py +0 -0
  121. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab_context.py +0 -0
  122. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab_discussions.py +0 -0
  123. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab_identity.py +0 -0
  124. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/providers/gitlab_remediation.py +0 -0
  125. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/py.typed +0 -0
  126. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/result_contract.py +0 -0
  127. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/result_usage.py +0 -0
  128. {open_code_review_toolkit-0.9.0 → open_code_review_toolkit-0.10.0}/src/ocr_toolkit/review_identity.py +0 -0
@@ -12,6 +12,7 @@ build/
12
12
  dist/
13
13
  .review-context/
14
14
  .quality-logs/
15
+ .tgrep-index/
15
16
  .idea/
16
17
  *.log
17
18
  .codex
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: open-code-review-toolkit
3
- Version: 0.9.0
3
+ Version: 0.10.0
4
4
  Summary: Unofficial GitLab CI integration layer for Open Code Review
5
5
  Project-URL: Homepage, https://github.com/xeonvs/open-code-review-toolkit
6
6
  Project-URL: Repository, https://github.com/xeonvs/open-code-review-toolkit
@@ -234,7 +234,7 @@ Description-Content-Type: text/markdown
234
234
  [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/xeonvs/open-code-review-toolkit/badge)](https://securityscorecards.dev/viewer/?uri=github.com/xeonvs/open-code-review-toolkit)
235
235
  [![CodeQL](https://github.com/xeonvs/open-code-review-toolkit/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/xeonvs/open-code-review-toolkit/actions/workflows/codeql.yml)
236
236
 
237
- Open Code Review Toolkit is an unofficial GitLab CI integration layer for [Alibaba Open Code Review](https://github.com/alibaba/open-code-review). It provides bounded repository evidence, a compact review bootstrap, a built-in read-only MCP server, environment-driven OCR configuration, preflight validation, and safe GitLab merge-request posting. It does **not** bundle or download the `ocr` binary.
237
+ Open Code Review Toolkit is an unofficial review control and integration layer for [Alibaba Open Code Review](https://github.com/alibaba/open-code-review), with GitLab CI and standalone local providers. It provides bounded repository evidence, a compact review bootstrap, a built-in read-only MCP server, environment-driven OCR configuration, preflight validation, local Markdown reports, and safe GitLab merge-request posting. It does **not** bundle or download the `ocr` binary.
238
238
 
239
239
  > [!NOTE]
240
240
  > The project is under active development; the public API, CLI, environment contract, and generated schemas may evolve before 1.0.
@@ -257,13 +257,12 @@ python -m venv .venv
257
257
  python -m pip install open-code-review-toolkit
258
258
  ```
259
259
 
260
- The toolkit does not bundle OCR. Download the platform asset for exact
261
- [Open Code Review 1.11.3](https://github.com/alibaba/open-code-review/releases/tag/v1.11.3),
262
- verify it before installation against the [compatibility manifest](compatibility/ocr-support.json),
263
- and place the verified binary on `PATH`. The current Linux amd64 digest is
264
- `9726204ac81baee153fd65b1ff357c380f73e9d8091c4a73c3c9fb541b5164cb`; Darwin arm64 is
265
- `515cd92ce300b62dea2bcaf53e910cdf57b681e1d58bbd0a9e8e49617bca52fa`. The manifest owns
266
- the other platform hashes.
260
+ The toolkit does not bundle OCR. Use `recommended_version` in the
261
+ [compatibility manifest](compatibility/ocr-support.json) for this toolkit revision
262
+ to select the exact [upstream release](https://github.com/alibaba/open-code-review/releases).
263
+ Download its platform asset, verify it against that release entry's asset SHA-256,
264
+ and place the verified binary on `PATH`. Do not substitute the latest upstream
265
+ release or use another toolkit revision's manifest.
267
266
 
268
267
  Verify the installation without contacting an LLM provider:
269
268
 
@@ -272,18 +271,41 @@ ocr --version
272
271
  ocr-ci --help
273
272
  ```
274
273
 
275
- `ocr --version` must report `open-code-review v1.11.3`; `ocr-ci --help` must exit
274
+ `ocr --version` must report the manifest's exact `recommended_version`; `ocr-ci --help` must exit
276
275
  successfully. `ocr-ci preflight` is an operational configuration check, not the installation
277
276
  smoke test.
278
277
 
279
278
  The exact recommended OCR release and its verified asset checksums live in the [versioned compatibility manifest](compatibility/ocr-support.json). CI should pin that release and checksum before execution.
280
279
  The [versioned compatibility policy](docs/compatibility.md) records tested assets and evidence and describes the conservative Dependabot-like qualification workflow for later upstream releases.
281
280
  Review output defaults to English. `OCR_REVIEW_LANGUAGE` accepts another explicit language name when a project needs localized review output; for example, `OCR_REVIEW_LANGUAGE=Russian`.
282
- The current OCR 1.11.3 integration defaults `OCR_REVIEW_EFFORT` to `medium` for two review rounds. `low` and `high` are explicit one- and three-round alternatives; see the [configuration reference](docs/configuration.md#review-effort) for cost, budget, and precedence boundaries.
281
+ The toolkit defaults `OCR_REVIEW_EFFORT` to `medium` for two review rounds. `low` and `high` are explicit one- and three-round alternatives; see the [configuration reference](docs/configuration.md#review-effort) for cost, budget, and precedence boundaries.
283
282
 
284
283
  Stable distributions are published to [PyPI](https://pypi.org/project/open-code-review-toolkit/) and mirrored as checksum-listed, provenance-attested assets in the corresponding [GitHub Release](https://github.com/xeonvs/open-code-review-toolkit/releases). Development snapshots are published only to TestPyPI.
285
284
 
286
- ## How reviews evolve
285
+ ## Standalone local quick start
286
+
287
+ With the qualified OCR binary and LLM environment configured, review an immutable
288
+ commit without forge credentials:
289
+
290
+ ```console
291
+ ocr-ci preflight --local
292
+ ocr-ci review --local --result review.json --stderr review.stderr --report review.md -- --commit HEAD
293
+ ```
294
+
295
+ Local execution uses the same OCR, mandatory evidence MCP, validation and DLP
296
+ pipeline as CI. It publishes every admitted finding to a fresh private Markdown
297
+ file and the console, without GitLab acquisition, suppression, approval or a
298
+ fabricated publication receipt. See [local review](docs/local.md) for ranges,
299
+ failure behavior and optional private `--debug-dir` bundles.
300
+
301
+ Optional [reasoning and progress controls](docs/configuration.md#provider-endpoint-and-completion-cap-contract)
302
+ do not change review rounds or budgets. Reasoning is unset by default; explicit
303
+ `none` is a wire value whose support depends on the provider/model. Progress is
304
+ off by default and emits only bounded toolkit phases to an interactive terminal
305
+ or an explicitly nonblocking embedding stream; a conventional CI stderr pipe is
306
+ intentionally not used because it can block a review.
307
+
308
+ ## How GitLab reviews evolve
287
309
 
288
310
  On a successful rerun, the toolkit replaces untouched OCR-only notes instead of accumulating stale reviews. A human reply transfers that discussion to the team: the conversation is preserved and a matching finding is suppressed. Reply with `/ocr suppress` or `@<live-bot-username> suppress` to keep a discussion open without future repeats; use the corresponding `resolve` command to resolve it after the next successful posting transaction. For example, a bot named `mr.bot` accepts the exact reply `@mr.bot resolve`.
289
311
 
@@ -7,7 +7,7 @@
7
7
  [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/xeonvs/open-code-review-toolkit/badge)](https://securityscorecards.dev/viewer/?uri=github.com/xeonvs/open-code-review-toolkit)
8
8
  [![CodeQL](https://github.com/xeonvs/open-code-review-toolkit/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/xeonvs/open-code-review-toolkit/actions/workflows/codeql.yml)
9
9
 
10
- Open Code Review Toolkit is an unofficial GitLab CI integration layer for [Alibaba Open Code Review](https://github.com/alibaba/open-code-review). It provides bounded repository evidence, a compact review bootstrap, a built-in read-only MCP server, environment-driven OCR configuration, preflight validation, and safe GitLab merge-request posting. It does **not** bundle or download the `ocr` binary.
10
+ Open Code Review Toolkit is an unofficial review control and integration layer for [Alibaba Open Code Review](https://github.com/alibaba/open-code-review), with GitLab CI and standalone local providers. It provides bounded repository evidence, a compact review bootstrap, a built-in read-only MCP server, environment-driven OCR configuration, preflight validation, local Markdown reports, and safe GitLab merge-request posting. It does **not** bundle or download the `ocr` binary.
11
11
 
12
12
  > [!NOTE]
13
13
  > The project is under active development; the public API, CLI, environment contract, and generated schemas may evolve before 1.0.
@@ -30,13 +30,12 @@ python -m venv .venv
30
30
  python -m pip install open-code-review-toolkit
31
31
  ```
32
32
 
33
- The toolkit does not bundle OCR. Download the platform asset for exact
34
- [Open Code Review 1.11.3](https://github.com/alibaba/open-code-review/releases/tag/v1.11.3),
35
- verify it before installation against the [compatibility manifest](compatibility/ocr-support.json),
36
- and place the verified binary on `PATH`. The current Linux amd64 digest is
37
- `9726204ac81baee153fd65b1ff357c380f73e9d8091c4a73c3c9fb541b5164cb`; Darwin arm64 is
38
- `515cd92ce300b62dea2bcaf53e910cdf57b681e1d58bbd0a9e8e49617bca52fa`. The manifest owns
39
- the other platform hashes.
33
+ The toolkit does not bundle OCR. Use `recommended_version` in the
34
+ [compatibility manifest](compatibility/ocr-support.json) for this toolkit revision
35
+ to select the exact [upstream release](https://github.com/alibaba/open-code-review/releases).
36
+ Download its platform asset, verify it against that release entry's asset SHA-256,
37
+ and place the verified binary on `PATH`. Do not substitute the latest upstream
38
+ release or use another toolkit revision's manifest.
40
39
 
41
40
  Verify the installation without contacting an LLM provider:
42
41
 
@@ -45,18 +44,41 @@ ocr --version
45
44
  ocr-ci --help
46
45
  ```
47
46
 
48
- `ocr --version` must report `open-code-review v1.11.3`; `ocr-ci --help` must exit
47
+ `ocr --version` must report the manifest's exact `recommended_version`; `ocr-ci --help` must exit
49
48
  successfully. `ocr-ci preflight` is an operational configuration check, not the installation
50
49
  smoke test.
51
50
 
52
51
  The exact recommended OCR release and its verified asset checksums live in the [versioned compatibility manifest](compatibility/ocr-support.json). CI should pin that release and checksum before execution.
53
52
  The [versioned compatibility policy](docs/compatibility.md) records tested assets and evidence and describes the conservative Dependabot-like qualification workflow for later upstream releases.
54
53
  Review output defaults to English. `OCR_REVIEW_LANGUAGE` accepts another explicit language name when a project needs localized review output; for example, `OCR_REVIEW_LANGUAGE=Russian`.
55
- The current OCR 1.11.3 integration defaults `OCR_REVIEW_EFFORT` to `medium` for two review rounds. `low` and `high` are explicit one- and three-round alternatives; see the [configuration reference](docs/configuration.md#review-effort) for cost, budget, and precedence boundaries.
54
+ The toolkit defaults `OCR_REVIEW_EFFORT` to `medium` for two review rounds. `low` and `high` are explicit one- and three-round alternatives; see the [configuration reference](docs/configuration.md#review-effort) for cost, budget, and precedence boundaries.
56
55
 
57
56
  Stable distributions are published to [PyPI](https://pypi.org/project/open-code-review-toolkit/) and mirrored as checksum-listed, provenance-attested assets in the corresponding [GitHub Release](https://github.com/xeonvs/open-code-review-toolkit/releases). Development snapshots are published only to TestPyPI.
58
57
 
59
- ## How reviews evolve
58
+ ## Standalone local quick start
59
+
60
+ With the qualified OCR binary and LLM environment configured, review an immutable
61
+ commit without forge credentials:
62
+
63
+ ```console
64
+ ocr-ci preflight --local
65
+ ocr-ci review --local --result review.json --stderr review.stderr --report review.md -- --commit HEAD
66
+ ```
67
+
68
+ Local execution uses the same OCR, mandatory evidence MCP, validation and DLP
69
+ pipeline as CI. It publishes every admitted finding to a fresh private Markdown
70
+ file and the console, without GitLab acquisition, suppression, approval or a
71
+ fabricated publication receipt. See [local review](docs/local.md) for ranges,
72
+ failure behavior and optional private `--debug-dir` bundles.
73
+
74
+ Optional [reasoning and progress controls](docs/configuration.md#provider-endpoint-and-completion-cap-contract)
75
+ do not change review rounds or budgets. Reasoning is unset by default; explicit
76
+ `none` is a wire value whose support depends on the provider/model. Progress is
77
+ off by default and emits only bounded toolkit phases to an interactive terminal
78
+ or an explicitly nonblocking embedding stream; a conventional CI stderr pipe is
79
+ intentionally not used because it can block a review.
80
+
81
+ ## How GitLab reviews evolve
60
82
 
61
83
  On a successful rerun, the toolkit replaces untouched OCR-only notes instead of accumulating stale reviews. A human reply transfers that discussion to the team: the conversation is preserved and a matching finding is suppressed. Reply with `/ocr suppress` or `@<live-bot-username> suppress` to keep a discussion open without future repeats; use the corresponding `resolve` command to resolve it after the next successful posting transaction. For example, a bot named `mr.bot` accepts the exact reply `@mr.bot resolve`.
62
84
 
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.9.0'
22
- __version_tuple__ = version_tuple = (0, 9, 0)
21
+ __version__ = version = '0.10.0'
22
+ __version_tuple__ = version_tuple = (0, 10, 0)
23
23
 
24
24
  __commit_id__ = commit_id = None
@@ -24,7 +24,12 @@ def build_parser() -> argparse.ArgumentParser:
24
24
  version=f"%(prog)s {__version__}",
25
25
  )
26
26
  subparsers = parser.add_subparsers(dest="command", required=True)
27
- subparsers.add_parser("preflight", help="Validate OCR, GitLab, and LLM access.")
27
+ preflight_parser = subparsers.add_parser(
28
+ "preflight", help="Validate review prerequisites and configured access."
29
+ )
30
+ preflight_parser.add_argument(
31
+ "--local", action="store_true", help="Validate standalone local review prerequisites."
32
+ )
28
33
  subparsers.add_parser("configure", help="Write the OCR runtime configuration.")
29
34
  subparsers.add_parser("mcp-config", help="Write OCR MCP server configuration.")
30
35
  review_parser = subparsers.add_parser(
@@ -32,6 +37,15 @@ def build_parser() -> argparse.ArgumentParser:
32
37
  )
33
38
  review_parser.add_argument("--result", required=True, help="OCR JSON output path.")
34
39
  review_parser.add_argument("--stderr", required=True, help="Full OCR stderr artifact path.")
40
+ review_parser.add_argument(
41
+ "--local", action="store_true", help="Review immutable Git refs and publish local Markdown."
42
+ )
43
+ review_parser.add_argument(
44
+ "--report", help="Fresh local Markdown path (default: --result path plus .md)."
45
+ )
46
+ review_parser.add_argument(
47
+ "--debug-dir", help="Fresh private diagnostic bundle directory (requires --local)."
48
+ )
35
49
  review_parser.add_argument(
36
50
  "--preserve-private-artifacts",
37
51
  action="store_true",
@@ -62,7 +76,7 @@ def main(argv: Sequence[str] | None = None) -> int:
62
76
 
63
77
  args = build_parser().parse_args(argv)
64
78
  if args.command == "preflight":
65
- return preflight.main()
79
+ return preflight.main(local=True) if args.local else preflight.main()
66
80
  if args.command == "configure":
67
81
  return configure.main()
68
82
  if args.command == "mcp-config":
@@ -75,6 +89,9 @@ def main(argv: Sequence[str] | None = None) -> int:
75
89
  Path(args.stderr),
76
90
  ocr_args,
77
91
  preserve_private_artifacts=args.preserve_private_artifacts,
92
+ **({"local": True} if args.local else {}),
93
+ **({"report_path": Path(args.report)} if args.report is not None else {}),
94
+ **({"debug_dir": Path(args.debug_dir)} if args.debug_dir is not None else {}),
78
95
  )
79
96
  except review_runner.ReviewRunnerError as exc:
80
97
  print(f"Cannot run Open Code Review: {exc}", file=sys.stderr)
@@ -0,0 +1,68 @@
1
+ """Small cross-platform filesystem durability helpers."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import errno
6
+ import os
7
+ import stat
8
+ from pathlib import Path
9
+
10
+
11
+ def fsync_directory(descriptor: int) -> None:
12
+ """Persist a directory-entry change when the platform supports it."""
13
+
14
+ try:
15
+ os.fsync(descriptor)
16
+ except OSError as exc:
17
+ # Some supported filesystems reject directory fsync even though the
18
+ # atomic rename itself succeeded. Ignore only documented unsupported
19
+ # descriptor/filesystem cases; propagate genuine durability failures.
20
+ if exc.errno not in {errno.EINVAL, errno.ENOTSUP, errno.EBADF}:
21
+ raise
22
+
23
+
24
+ def open_private_parent_directory(path: Path) -> tuple[int, str]:
25
+ """Open a path's parent without following replaceable pathname components.
26
+
27
+ The returned descriptor pins the parent directory. Callers must use
28
+ descriptor-relative operations and close it themselves; returning an
29
+ absolute pathname would reintroduce the ancestor replacement race this
30
+ helper avoids.
31
+ """
32
+
33
+ absolute = path.absolute()
34
+ parts = [part for part in absolute.parts if part != os.path.sep]
35
+ if not parts:
36
+ raise ValueError("private output path must name a file or directory")
37
+ descriptor = os.open(os.path.sep, os.O_RDONLY | os.O_DIRECTORY)
38
+ try:
39
+ for component in parts[:-1]:
40
+ flags = os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW
41
+ try:
42
+ child = os.open(component, flags, dir_fd=descriptor)
43
+ except FileNotFoundError:
44
+ try:
45
+ os.mkdir(component, mode=0o700, dir_fd=descriptor)
46
+ except FileExistsError:
47
+ pass
48
+ try:
49
+ child = os.open(component, flags, dir_fd=descriptor)
50
+ except OSError as exc:
51
+ raise ValueError("private output parent must not be a symlink") from exc
52
+ except OSError as exc:
53
+ raise ValueError("private output parent must not be a symlink") from exc
54
+ os.close(descriptor)
55
+ descriptor = child
56
+ parent = os.fstat(descriptor)
57
+ if not stat.S_ISDIR(parent.st_mode):
58
+ raise OSError("private output parent is not a directory")
59
+ return descriptor, parts[-1]
60
+ except BaseException:
61
+ os.close(descriptor)
62
+ raise
63
+
64
+
65
+ def same_file_identity(left: os.stat_result, right: os.stat_result) -> bool:
66
+ """Compare two pinned filesystem identities without following pathnames."""
67
+
68
+ return left.st_dev == right.st_dev and left.st_ino == right.st_ino
@@ -0,0 +1,21 @@
1
+ """Posting facade for shared report value normalization."""
2
+
3
+ from ocr_toolkit.reporting.text import (
4
+ clean_text,
5
+ code_text,
6
+ comment_line,
7
+ compact_control_text,
8
+ compact_escaped_text,
9
+ compact_text,
10
+ line_number,
11
+ )
12
+
13
+ __all__ = [
14
+ "clean_text",
15
+ "code_text",
16
+ "comment_line",
17
+ "compact_control_text",
18
+ "compact_escaped_text",
19
+ "compact_text",
20
+ "line_number",
21
+ ]