devcontour-harness 0.1.0-alpha.5 → 0.1.0-alpha.7

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 (263) hide show
  1. package/README.md +42 -2
  2. package/docs/compatibility-versions.md +56 -0
  3. package/docs/compatibility.md +2 -2
  4. package/docs/connectors.md +323 -0
  5. package/docs/contracts.md +33 -5
  6. package/docs/integrations/hindsight.md +148 -0
  7. package/docs/quickstart.md +1 -1
  8. package/docs/release-notes/0.1.0-alpha.6.md +238 -0
  9. package/docs/release-notes/0.1.0-alpha.7.md +71 -0
  10. package/docs/review-probes.md +199 -0
  11. package/docs/review-protocol.md +251 -0
  12. package/docs/toolchains.md +167 -0
  13. package/docs/turbo-starter.md +269 -0
  14. package/docs/upgrade.md +77 -24
  15. package/examples/README.md +1 -0
  16. package/examples/toolchains/README.md +32 -0
  17. package/examples/toolchains/go/bad/label/label.go +9 -0
  18. package/examples/toolchains/go/good/label/label.go +9 -0
  19. package/examples/toolchains/go/policy.json +79 -0
  20. package/examples/toolchains/go/repo/REQUIREMENTS.md +9 -0
  21. package/examples/toolchains/go/repo/_gitignore +1 -0
  22. package/examples/toolchains/go/repo/go.mod +5 -0
  23. package/examples/toolchains/go/repo/go.sum +2 -0
  24. package/examples/toolchains/go/repo/label/label.go +9 -0
  25. package/examples/toolchains/go/repo/label/label_test.go +27 -0
  26. package/examples/toolchains/go/repo/label/version.go +9 -0
  27. package/examples/toolchains/go/task.json +25 -0
  28. package/examples/toolchains/mixed-go/bad/backend/label/label.go +9 -0
  29. package/examples/toolchains/mixed-go/bad/frontend/src/label.js +4 -0
  30. package/examples/toolchains/mixed-go/good/backend/label/label.go +9 -0
  31. package/examples/toolchains/mixed-go/good/frontend/src/label.js +4 -0
  32. package/examples/toolchains/mixed-go/policy.json +126 -0
  33. package/examples/toolchains/mixed-go/repo/REQUIREMENTS.md +9 -0
  34. package/examples/toolchains/mixed-go/repo/_gitignore +6 -0
  35. package/examples/toolchains/mixed-go/repo/backend/go.mod +3 -0
  36. package/examples/toolchains/mixed-go/repo/backend/label/label.go +9 -0
  37. package/examples/toolchains/mixed-go/repo/backend/label/label_test.go +30 -0
  38. package/examples/toolchains/mixed-go/repo/contract/check.mjs +17 -0
  39. package/examples/toolchains/mixed-go/repo/contract/label.json +9 -0
  40. package/examples/toolchains/mixed-go/repo/frontend/package.json +15 -0
  41. package/examples/toolchains/mixed-go/repo/frontend/pnpm-lock.yaml +22 -0
  42. package/examples/toolchains/mixed-go/repo/frontend/src/label.js +4 -0
  43. package/examples/toolchains/mixed-go/repo/frontend/test/label.test.js +11 -0
  44. package/examples/toolchains/mixed-go/task.json +25 -0
  45. package/examples/toolchains/mixed-python/bad/backend/src/fx_backend/__init__.py +6 -0
  46. package/examples/toolchains/mixed-python/bad/frontend/src/label.js +4 -0
  47. package/examples/toolchains/mixed-python/good/backend/src/fx_backend/__init__.py +6 -0
  48. package/examples/toolchains/mixed-python/good/frontend/src/label.js +4 -0
  49. package/examples/toolchains/mixed-python/policy.json +121 -0
  50. package/examples/toolchains/mixed-python/repo/REQUIREMENTS.md +9 -0
  51. package/examples/toolchains/mixed-python/repo/_gitignore +6 -0
  52. package/examples/toolchains/mixed-python/repo/backend/.python-version +1 -0
  53. package/examples/toolchains/mixed-python/repo/backend/pyproject.toml +19 -0
  54. package/examples/toolchains/mixed-python/repo/backend/src/fx_backend/__init__.py +6 -0
  55. package/examples/toolchains/mixed-python/repo/backend/tests/test_label.py +11 -0
  56. package/examples/toolchains/mixed-python/repo/backend/uv.lock +108 -0
  57. package/examples/toolchains/mixed-python/repo/contract/check.mjs +17 -0
  58. package/examples/toolchains/mixed-python/repo/contract/label.json +9 -0
  59. package/examples/toolchains/mixed-python/repo/frontend/package.json +15 -0
  60. package/examples/toolchains/mixed-python/repo/frontend/pnpm-lock.yaml +22 -0
  61. package/examples/toolchains/mixed-python/repo/frontend/src/label.js +4 -0
  62. package/examples/toolchains/mixed-python/repo/frontend/test/label.test.js +11 -0
  63. package/examples/toolchains/mixed-python/task.json +25 -0
  64. package/examples/toolchains/npm/bad/src/label.js +4 -0
  65. package/examples/toolchains/npm/good/src/label.js +4 -0
  66. package/examples/toolchains/npm/policy.json +82 -0
  67. package/examples/toolchains/npm/repo/REQUIREMENTS.md +9 -0
  68. package/examples/toolchains/npm/repo/_gitignore +4 -0
  69. package/examples/toolchains/npm/repo/package-lock.json +22 -0
  70. package/examples/toolchains/npm/repo/package.json +13 -0
  71. package/examples/toolchains/npm/repo/src/label.js +4 -0
  72. package/examples/toolchains/npm/repo/test/label.test.js +13 -0
  73. package/examples/toolchains/npm/task.json +25 -0
  74. package/examples/toolchains/pnpm/bad/packages/label/src/label.js +4 -0
  75. package/examples/toolchains/pnpm/good/packages/label/src/label.js +4 -0
  76. package/examples/toolchains/pnpm/policy.json +85 -0
  77. package/examples/toolchains/pnpm/repo/REQUIREMENTS.md +9 -0
  78. package/examples/toolchains/pnpm/repo/_gitignore +4 -0
  79. package/examples/toolchains/pnpm/repo/package.json +10 -0
  80. package/examples/toolchains/pnpm/repo/packages/checker/check.mjs +5 -0
  81. package/examples/toolchains/pnpm/repo/packages/checker/package.json +9 -0
  82. package/examples/toolchains/pnpm/repo/packages/label/package.json +14 -0
  83. package/examples/toolchains/pnpm/repo/packages/label/src/label.js +4 -0
  84. package/examples/toolchains/pnpm/repo/packages/label/test/label.test.js +13 -0
  85. package/examples/toolchains/pnpm/repo/pnpm-lock.yaml +29 -0
  86. package/examples/toolchains/pnpm/repo/pnpm-workspace.yaml +2 -0
  87. package/examples/toolchains/pnpm/task.json +25 -0
  88. package/examples/toolchains/python/bad/src/fx_label/__init__.py +6 -0
  89. package/examples/toolchains/python/good/src/fx_label/__init__.py +6 -0
  90. package/examples/toolchains/python/policy.json +80 -0
  91. package/examples/toolchains/python/repo/.python-version +1 -0
  92. package/examples/toolchains/python/repo/REQUIREMENTS.md +9 -0
  93. package/examples/toolchains/python/repo/_gitignore +5 -0
  94. package/examples/toolchains/python/repo/pyproject.toml +19 -0
  95. package/examples/toolchains/python/repo/src/fx_label/__init__.py +6 -0
  96. package/examples/toolchains/python/repo/tests/test_label.py +13 -0
  97. package/examples/toolchains/python/repo/uv.lock +108 -0
  98. package/examples/toolchains/python/task.json +25 -0
  99. package/examples/toolchains/turbo/bad/packages/label/src/label.js +4 -0
  100. package/examples/toolchains/turbo/good/packages/label/src/label.js +4 -0
  101. package/examples/toolchains/turbo/policy.json +110 -0
  102. package/examples/toolchains/turbo/repo/REQUIREMENTS.md +9 -0
  103. package/examples/toolchains/turbo/repo/_gitignore +4 -0
  104. package/examples/toolchains/turbo/repo/package.json +13 -0
  105. package/examples/toolchains/turbo/repo/packages/checker/check.mjs +5 -0
  106. package/examples/toolchains/turbo/repo/packages/checker/package.json +9 -0
  107. package/examples/toolchains/turbo/repo/packages/label/package.json +14 -0
  108. package/examples/toolchains/turbo/repo/packages/label/src/label.js +4 -0
  109. package/examples/toolchains/turbo/repo/packages/label/test/label.test.js +13 -0
  110. package/examples/toolchains/turbo/repo/pnpm-lock.yaml +94 -0
  111. package/examples/toolchains/turbo/repo/pnpm-workspace.yaml +2 -0
  112. package/examples/toolchains/turbo/repo/turbo.json +7 -0
  113. package/examples/toolchains/turbo/task.json +25 -0
  114. package/examples/turbo-starter/README.md +16 -0
  115. package/examples/turbo-starter/changes/issued-at-consumer-only.patch +12 -0
  116. package/examples/turbo-starter/changes/issued-at.patch +130 -0
  117. package/examples/turbo-starter/cleanup.mjs +58 -0
  118. package/examples/turbo-starter/graph.json +32 -0
  119. package/examples/turbo-starter/harness/acceptance/db-isolation.test.mjs +97 -0
  120. package/examples/turbo-starter/harness/acceptance/env-probe.test.mjs +75 -0
  121. package/examples/turbo-starter/harness/acceptance/generation.test.mjs +54 -0
  122. package/examples/turbo-starter/harness/acceptance/issued-at.test.mjs +43 -0
  123. package/examples/turbo-starter/harness/acceptance/lifecycle-probe.test.mjs +47 -0
  124. package/examples/turbo-starter/harness/compose-bridge.mjs +593 -0
  125. package/examples/turbo-starter/harness/compose.acceptance.yml +23 -0
  126. package/examples/turbo-starter/harness/env/backend.env.template +7 -0
  127. package/examples/turbo-starter/harness/env/compose.env.template +6 -0
  128. package/examples/turbo-starter/policy.json +109 -0
  129. package/examples/turbo-starter/policy.lifecycle.json +114 -0
  130. package/examples/turbo-starter/setup.mjs +352 -0
  131. package/lib/agents/cli-adapter.js +10 -1
  132. package/lib/agents/inspect.d.ts +56 -2
  133. package/lib/agents/inspect.js +264 -14
  134. package/lib/agents/review-probe.d.ts +229 -7
  135. package/lib/agents/review-probe.js +830 -72
  136. package/lib/agents/schemas.d.ts +3 -1
  137. package/lib/agents/schemas.js +7 -3
  138. package/lib/cli.js +167 -7
  139. package/lib/contracts/cli.d.ts +820 -11
  140. package/lib/contracts/cli.js +243 -4
  141. package/lib/contracts/errors.d.ts +3 -1
  142. package/lib/contracts/errors.js +2 -0
  143. package/lib/contracts/events.d.ts +37 -5
  144. package/lib/contracts/events.js +9 -0
  145. package/lib/contracts/execution.d.ts +389 -15
  146. package/lib/contracts/execution.js +76 -4
  147. package/lib/contracts/failure.js +5 -0
  148. package/lib/contracts/index.d.ts +1 -0
  149. package/lib/contracts/index.js +1 -0
  150. package/lib/contracts/policy.d.ts +15 -0
  151. package/lib/contracts/policy.js +10 -0
  152. package/lib/contracts/ports.d.ts +50 -0
  153. package/lib/contracts/profiles.d.ts +14 -0
  154. package/lib/contracts/profiles.js +4 -0
  155. package/lib/contracts/published.d.ts +279 -8
  156. package/lib/contracts/result.d.ts +171 -0
  157. package/lib/contracts/result.js +39 -1
  158. package/lib/contracts/review.d.ts +231 -0
  159. package/lib/contracts/review.js +326 -2
  160. package/lib/contracts/toolchain.d.ts +96 -0
  161. package/lib/contracts/toolchain.js +89 -0
  162. package/lib/control/doctor.d.ts +16 -1
  163. package/lib/control/doctor.js +45 -3
  164. package/lib/control/harness.d.ts +52 -6
  165. package/lib/control/harness.js +28 -1
  166. package/lib/control/recovery.d.ts +3 -1
  167. package/lib/control/review.js +23 -11
  168. package/lib/engine/budget.d.ts +3 -3
  169. package/lib/engine/classify.js +1 -0
  170. package/lib/engine/engine.d.ts +67 -17
  171. package/lib/engine/prompt.d.ts +29 -1
  172. package/lib/engine/prompt.js +57 -0
  173. package/lib/engine/property-recovery.js +2 -0
  174. package/lib/engine/result.js +52 -0
  175. package/lib/engine/reuse.js +6 -1
  176. package/lib/engine/runner.d.ts +25 -0
  177. package/lib/engine/runner.js +500 -123
  178. package/lib/environment/lifecycle.js +6 -0
  179. package/lib/environment/live-calls.js +3 -2
  180. package/lib/environment/os-tools.d.ts +16 -0
  181. package/lib/environment/os-tools.js +35 -0
  182. package/lib/environment/process.d.ts +8 -0
  183. package/lib/environment/process.js +13 -6
  184. package/lib/integrations/connector/commands.d.ts +358 -0
  185. package/lib/integrations/connector/commands.js +428 -0
  186. package/lib/integrations/connector/config.d.ts +215 -0
  187. package/lib/integrations/connector/config.js +214 -0
  188. package/lib/integrations/connector/delivery.d.ts +107 -0
  189. package/lib/integrations/connector/delivery.js +591 -0
  190. package/lib/integrations/connector/fake.d.ts +291 -0
  191. package/lib/integrations/connector/fake.js +786 -0
  192. package/lib/integrations/connector/history.d.ts +124 -0
  193. package/lib/integrations/connector/history.js +497 -0
  194. package/lib/integrations/connector/index.d.ts +16 -0
  195. package/lib/integrations/connector/index.js +16 -0
  196. package/lib/integrations/connector/redact.d.ts +19 -0
  197. package/lib/integrations/connector/redact.js +91 -0
  198. package/lib/integrations/connector/registry.d.ts +15 -0
  199. package/lib/integrations/connector/registry.js +43 -0
  200. package/lib/integrations/connector/snapshot.d.ts +131 -0
  201. package/lib/integrations/connector/snapshot.js +422 -0
  202. package/lib/integrations/connector/source.d.ts +37 -0
  203. package/lib/integrations/connector/source.js +73 -0
  204. package/lib/integrations/connector/steps.d.ts +71 -0
  205. package/lib/integrations/connector/steps.js +188 -0
  206. package/lib/integrations/connector/store.d.ts +140 -0
  207. package/lib/integrations/connector/store.js +277 -0
  208. package/lib/integrations/connector/summary.d.ts +38 -0
  209. package/lib/integrations/connector/summary.js +59 -0
  210. package/lib/integrations/connector/testing-worker.d.ts +1 -0
  211. package/lib/integrations/connector/testing-worker.js +81 -0
  212. package/lib/integrations/connector/testing.d.ts +205 -0
  213. package/lib/integrations/connector/testing.js +1615 -0
  214. package/lib/integrations/connector/transport.d.ts +240 -0
  215. package/lib/integrations/connector/transport.js +28 -0
  216. package/lib/integrations/memory/context.d.ts +120 -0
  217. package/lib/integrations/memory/context.js +239 -0
  218. package/lib/integrations/memory/index.d.ts +8 -0
  219. package/lib/integrations/memory/index.js +8 -0
  220. package/lib/integrations/memory/provider.d.ts +79 -0
  221. package/lib/integrations/memory/provider.js +22 -0
  222. package/lib/integrations/memory/sink.d.ts +56 -0
  223. package/lib/integrations/memory/sink.js +116 -0
  224. package/lib/integrations/memory/testing.d.ts +44 -0
  225. package/lib/integrations/memory/testing.js +61 -0
  226. package/lib/integrations/relay-v1/index.d.ts +122 -0
  227. package/lib/integrations/relay-v1/index.js +860 -0
  228. package/lib/integrations/relay-v2/index.d.ts +145 -0
  229. package/lib/integrations/relay-v2/index.js +752 -0
  230. package/lib/integrations/relay-v2/process.d.ts +32 -0
  231. package/lib/integrations/relay-v2/process.js +112 -0
  232. package/lib/integrations/relay-v2/protocol.d.ts +172 -0
  233. package/lib/integrations/relay-v2/protocol.js +142 -0
  234. package/lib/profiles/resolve.d.ts +5 -1
  235. package/lib/profiles/resolve.js +31 -0
  236. package/lib/storage/document.d.ts +116 -16
  237. package/lib/toolchains/index.d.ts +9 -0
  238. package/lib/toolchains/index.js +9 -0
  239. package/lib/toolchains/inspect.d.ts +105 -0
  240. package/lib/toolchains/inspect.js +831 -0
  241. package/lib/toolchains/manifests.d.ts +67 -0
  242. package/lib/toolchains/manifests.js +238 -0
  243. package/lib/toolchains/probe.d.ts +28 -0
  244. package/lib/toolchains/probe.js +54 -0
  245. package/lib/toolchains/recipes.d.ts +33 -0
  246. package/lib/toolchains/recipes.js +51 -0
  247. package/lib/verification/acceptance.d.ts +16 -0
  248. package/lib/verification/acceptance.js +16 -0
  249. package/lib/verification/gates.d.ts +38 -0
  250. package/lib/verification/gates.js +108 -26
  251. package/package.json +22 -1
  252. package/profiles/go-gotestsum.json +21 -0
  253. package/profiles/npm-ci.json +22 -0
  254. package/profiles/pnpm-frozen.json +24 -0
  255. package/profiles/python-uv.json +26 -0
  256. package/schemas/execution-document.schema.json +345 -4
  257. package/schemas/execution-policy.schema.json +48 -0
  258. package/schemas/result-envelope.schema.json +213 -1
  259. package/schemas/run-event.schema.json +93 -0
  260. package/schemas/run-result.schema.json +207 -0
  261. package/schemas/stack-profile.schema.json +43 -0
  262. package/templates/controller-mode/AGENTS.controller.md +58 -0
  263. package/templates/controller-mode/README.md +44 -0
@@ -1,6 +1,6 @@
1
1
  import { type Author, type ContextSnapshot, type ContractDocument, type PropertyRecovery, type ExecutionPolicy, type ResultEnvelope, type ResultSink, type WorkSource, type RuntimeAdapter, type RuntimeName, type WorkGraph } from '../contracts/index.ts';
2
2
  import { Engine } from '../engine/engine.ts';
3
- import { Runner } from '../engine/runner.ts';
3
+ import { Runner, type RunnerHooks } from '../engine/runner.ts';
4
4
  import { SqliteExecutionStore } from '../storage/sqlite.ts';
5
5
  import { WorkflowQueue } from './workflow.ts';
6
6
  import { type PolicySource } from './provenance.ts';
@@ -15,6 +15,11 @@ export interface HarnessOptions {
15
15
  adapters?: Partial<Record<RuntimeName, RuntimeAdapter>>;
16
16
  /** Читающие операции не создают каталог состояния. */
17
17
  readOnly?: boolean;
18
+ /**
19
+ * Открыть базу состояния только для чтения (status, events, result): процесс
20
+ * не записывает даже метку писателя. Любая запись — отказ.
21
+ */
22
+ readOnlyState?: boolean;
18
23
  environment?: NodeJS.ProcessEnv;
19
24
  /**
20
25
  * Файл, из которого загружена политика. С ним процесс может записать свою
@@ -24,6 +29,12 @@ export interface HarnessOptions {
24
29
  policySource?: PolicySource;
25
30
  /** База блокировок ресурсов; по умолчанию — общая для машины. */
26
31
  resourceDatabase?: string;
32
+ /**
33
+ * Дополнения хоста к попыткам (например, история работы внешнего
34
+ * хранилища задач до исполнения). Приёмку не решают: отказ хука — отказ
35
+ * попытки.
36
+ */
37
+ hooks?: RunnerHooks;
27
38
  }
28
39
  /**
29
40
  * Доменные операции harness — общие для библиотеки и CLI. Здесь нет
@@ -553,7 +564,7 @@ export declare class Harness {
553
564
  basis: string;
554
565
  runs: string[];
555
566
  openedAt: string;
556
- status: "stopped" | "closed" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
567
+ status: "closed" | "stopped" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
557
568
  calls: number;
558
569
  history: {
559
570
  at: string;
@@ -724,7 +735,7 @@ export declare class Harness {
724
735
  pauseReason?: "runtime" | "operator" | "shutdown" | "base-check" | "reconfigure" | undefined;
725
736
  pausedAt?: string | undefined;
726
737
  pauseOperation?: string | undefined;
727
- pauseFailures?: ("gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "merge" | "budget")[] | undefined;
738
+ pauseFailures?: ("gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "review-protocol" | "merge" | "budget")[] | undefined;
728
739
  waits?: {
729
740
  kind: "base-check" | "context-lock";
730
741
  detail: string;
@@ -781,7 +792,7 @@ export declare class Harness {
781
792
  pauseReason?: "runtime" | "operator" | "shutdown" | "base-check" | "reconfigure" | undefined;
782
793
  pausedAt?: string | undefined;
783
794
  pauseOperation?: string | undefined;
784
- pauseFailures?: ("gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "merge" | "budget")[] | undefined;
795
+ pauseFailures?: ("gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "review-protocol" | "merge" | "budget")[] | undefined;
785
796
  waits?: {
786
797
  kind: "base-check" | "context-lock";
787
798
  detail: string;
@@ -928,6 +939,21 @@ export declare class Harness {
928
939
  sameVendor: boolean;
929
940
  model?: string | undefined;
930
941
  } | undefined;
942
+ review?: {
943
+ round: number;
944
+ call: number;
945
+ protocol: "valid" | "invalid" | "unsafe";
946
+ issues?: {
947
+ path: string;
948
+ reason: string;
949
+ message: string;
950
+ }[] | undefined;
951
+ transitions?: {
952
+ id: string;
953
+ from: "open" | "closed" | "withdrawn";
954
+ to: "open" | "closed" | "withdrawn";
955
+ }[] | undefined;
956
+ } | undefined;
931
957
  }[];
932
958
  findings: {
933
959
  severity: string;
@@ -935,6 +961,8 @@ export declare class Harness {
935
961
  path?: string | null | undefined;
936
962
  line?: number | null | undefined;
937
963
  rule?: string | undefined;
964
+ id?: string | undefined;
965
+ status?: "open" | "closed" | "withdrawn" | undefined;
938
966
  }[];
939
967
  limitations: string[];
940
968
  finishedAt: string;
@@ -946,7 +974,7 @@ export declare class Harness {
946
974
  integration?: string | undefined;
947
975
  };
948
976
  stopReason: {
949
- code: "INVALID_INPUT" | "UNSUPPORTED_COMMAND" | "UNSUPPORTED_VERSION" | "GRAPH_CYCLE" | "GRAPH_UNKNOWN_DEPENDENCY" | "GRAPH_DUPLICATE_ID" | "GATE_UNKNOWN" | "GATE_GROUP_CYCLE" | "REVIEWER_SAME_VENDOR" | "REVIEWER_MISSING" | "APPROVAL_STALE" | "APPROVAL_REQUIRED" | "LEASE_STALE" | "CONTROLLER_BUSY" | "PAUSED" | "NOT_READY" | "SCOPE_VIOLATION" | "GATE_FAILED" | "REVIEW_REJECTED" | "BUDGET_EXHAUSTED" | "BUDGET_UNKNOWN" | "ATTEMPTS_EXHAUSTED" | "REVISION_CONFLICT" | "CANCELLED" | "NOT_FOUND" | "STATE_VERSION_UNSUPPORTED" | "RUNTIME_UNAVAILABLE" | "SANDBOX_UNAVAILABLE" | "GIT_FAILED" | "STORAGE_FAILED" | "DELIVERY_FAILED" | "INTERNAL";
977
+ code: "INVALID_INPUT" | "UNSUPPORTED_COMMAND" | "UNSUPPORTED_VERSION" | "GRAPH_CYCLE" | "GRAPH_UNKNOWN_DEPENDENCY" | "GRAPH_DUPLICATE_ID" | "GATE_UNKNOWN" | "GATE_GROUP_CYCLE" | "REVIEWER_SAME_VENDOR" | "REVIEWER_MISSING" | "APPROVAL_STALE" | "APPROVAL_REQUIRED" | "LEASE_STALE" | "CONTROLLER_BUSY" | "PAUSED" | "NOT_READY" | "SCOPE_VIOLATION" | "GATE_FAILED" | "REVIEW_REJECTED" | "BUDGET_EXHAUSTED" | "BUDGET_UNKNOWN" | "ATTEMPTS_EXHAUSTED" | "REVISION_CONFLICT" | "CANCELLED" | "NOT_FOUND" | "STATE_VERSION_UNSUPPORTED" | "RUNTIME_UNAVAILABLE" | "REVIEW_PROTOCOL_INVALID" | "SANDBOX_UNAVAILABLE" | "GIT_FAILED" | "STORAGE_FAILED" | "DELIVERY_FAILED" | "INTERNAL";
950
978
  message: string;
951
979
  };
952
980
  apiVersion: "devcontour-harness/v1alpha1";
@@ -1052,6 +1080,21 @@ export declare class Harness {
1052
1080
  sameVendor: boolean;
1053
1081
  model?: string | undefined;
1054
1082
  } | undefined;
1083
+ review?: {
1084
+ round: number;
1085
+ call: number;
1086
+ protocol: "valid" | "invalid" | "unsafe";
1087
+ issues?: {
1088
+ path: string;
1089
+ reason: string;
1090
+ message: string;
1091
+ }[] | undefined;
1092
+ transitions?: {
1093
+ id: string;
1094
+ from: "open" | "closed" | "withdrawn";
1095
+ to: "open" | "closed" | "withdrawn";
1096
+ }[] | undefined;
1097
+ } | undefined;
1055
1098
  }[];
1056
1099
  findings: {
1057
1100
  severity: string;
@@ -1059,6 +1102,8 @@ export declare class Harness {
1059
1102
  path?: string | null | undefined;
1060
1103
  line?: number | null | undefined;
1061
1104
  rule?: string | undefined;
1105
+ id?: string | undefined;
1106
+ status?: "open" | "closed" | "withdrawn" | undefined;
1062
1107
  }[];
1063
1108
  limitations: string[];
1064
1109
  finishedAt: string;
@@ -1067,10 +1112,11 @@ export declare class Harness {
1067
1112
  sink: string;
1068
1113
  key: string;
1069
1114
  revision: string;
1070
- status: "failed" | "pending" | "delivered" | "conflict";
1115
+ status: "failed" | "pending" | "delivered" | "conflict" | "uncertain";
1071
1116
  attempts: number;
1072
1117
  updatedAt: string;
1073
1118
  lastError?: string | undefined;
1119
+ operation?: string | undefined;
1074
1120
  currentRevision?: string | undefined;
1075
1121
  receipt?: string | undefined;
1076
1122
  }[];
@@ -48,7 +48,9 @@ export class Harness {
48
48
  this.policy = options.policy;
49
49
  if (!options.readOnly)
50
50
  mkdirSync(options.stateDir, { recursive: true });
51
- this.store = new SqliteExecutionStore(stateFile(options.stateDir), 'devcontour-harness@' + HARNESS_VERSION);
51
+ this.store = new SqliteExecutionStore(stateFile(options.stateDir), 'devcontour-harness@' + HARNESS_VERSION,
52
+ // Только чтение состояния: процесс не становится писателем (meta, PRAGMA и данные прежние).
53
+ { readOnly: Boolean(options.readOnlyState) });
52
54
  const source = options.policySource;
53
55
  this.engine = new Engine({
54
56
  host: standaloneHost(this.store, this.policy),
@@ -68,6 +70,7 @@ export class Harness {
68
70
  context: (work) => this.contextOf(work.graphId),
69
71
  ...(options.environment ? { environment: options.environment } : {}),
70
72
  ...(options.resourceDatabase ? { resourceDatabase: options.resourceDatabase } : {}),
73
+ ...(options.hooks ? { hooks: options.hooks } : {}),
71
74
  });
72
75
  this.joint = new JointRunner({
73
76
  engine: this.engine,
@@ -652,6 +655,11 @@ export class Harness {
652
655
  updatedAt: new Date().toISOString(),
653
656
  };
654
657
  const save = (state, type) => this.store.transact('delivery.recorded', (tx) => {
658
+ // Подтверждённую доставку не перезаписывает поздний итог другого
659
+ // процесса (например, отказ «владелец занят» при параллельной доставке).
660
+ if (state.status !== 'delivered' &&
661
+ tx.local('delivery', WORKSPACE_OWNER, key)?.status === 'delivered')
662
+ return;
655
663
  tx.putLocal('delivery', WORKSPACE_OWNER, key, state);
656
664
  const payload = {
657
665
  sink: state.sink,
@@ -667,6 +675,16 @@ export class Harness {
667
675
  });
668
676
  else if (type === 'delivery.failed')
669
677
  tx.emit({ type, workId, payload: { ...payload, error: state.lastError ?? 'ошибка' } });
678
+ else if (type === 'delivery.uncertain')
679
+ tx.emit({
680
+ type,
681
+ workId,
682
+ payload: {
683
+ ...payload,
684
+ operation: state.operation ?? 'unknown',
685
+ reason: state.lastError ?? 'исход не доказан',
686
+ },
687
+ });
670
688
  else if (type === 'delivery.conflict')
671
689
  tx.emit({
672
690
  type,
@@ -687,6 +705,15 @@ export class Harness {
687
705
  status: 'delivered',
688
706
  ...(outcome.receipt ? { receipt: outcome.receipt.slice(0, 1000) } : {}),
689
707
  }, 'delivery.delivered');
708
+ else if (outcome.status === 'uncertain')
709
+ // Неизвестный исход — не успех и не отказ: повтор не посылает мутацию
710
+ // до явного разбора получателем (reconcile).
711
+ save({
712
+ ...attempt,
713
+ status: 'uncertain',
714
+ operation: outcome.operation.slice(0, 300),
715
+ lastError: ('Исход не доказан: ' + outcome.reason).slice(0, 4000),
716
+ }, 'delivery.uncertain');
690
717
  else
691
718
  save({
692
719
  ...attempt,
@@ -180,13 +180,15 @@ export declare function recoveryBrief(view: ExecutionView, work: WorkState, poli
180
180
  attempts: {
181
181
  run: string;
182
182
  attempt: number;
183
- failureKind: "gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "merge" | "budget" | undefined;
183
+ failureKind: "gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "review-protocol" | "merge" | "budget" | undefined;
184
184
  error: string | undefined;
185
185
  findings: {
186
186
  severity: string;
187
187
  message: string;
188
188
  path?: string | null | undefined;
189
189
  line?: number | null | undefined;
190
+ id?: string | undefined;
191
+ status?: "open" | "closed" | "withdrawn" | undefined;
190
192
  }[];
191
193
  durationMs: number | null;
192
194
  }[];
@@ -3,6 +3,7 @@ import { mkdir, writeFile } from 'node:fs/promises';
3
3
  import { join } from 'node:path';
4
4
  import { HarnessError, WORKSPACE_OWNER, contextDigest, findingId, mcpEnvironment, reviewIssues, reviewResultSchema, selectReviewer, } from "../contracts/index.js";
5
5
  import { reviewOutputSchema } from "../agents/schemas.js";
6
+ import { redactInspection } from "../agents/inspect.js";
6
7
  import { executionEnvironment } from "../environment/lifecycle.js";
7
8
  import { redactDeep } from "../environment/redaction.js";
8
9
  import { TaskFailure } from "../engine/failure.js";
@@ -112,16 +113,24 @@ export async function technicalReview(engine, policy, adapters, input) {
112
113
  throw new HarnessError('RUNTIME_UNAVAILABLE', `Ревью ${kind}: ${response.status}${response.diagnostics.reason ? ': ' + response.diagnostics.reason : ''}`);
113
114
  const parsed = reviewResultSchema.safeParse(response.output);
114
115
  const issues = parsed.success ? reviewIssues(parsed.data, open) : ['Ответ ревью вне схемы'];
115
- const transitions = new Map((parsed.success ? parsed.data.previous : []).map((t) => [t.id, t]));
116
+ // Ответ применяется только целиком валидным (docs/review-protocol.md, §8):
117
+ // невалидный не закрывает прежних находок и не заводит новых — раунд
118
+ // записывается неодобренным с причинами, история остаётся прежней.
119
+ const applied = parsed.success && !issues.length ? parsed.data : undefined;
120
+ const transitions = new Map((applied?.previous ?? []).map((t) => [t.id, t]));
121
+ const reported = (applied?.findings ?? []).map((f) => ({ ...f, id: findingId(subject, f) }));
116
122
  const findings = [
117
123
  ...lastFindings.map((f) => {
118
124
  const t = transitions.get(f.id);
119
- return f.status === 'open' && t
120
- ? { ...f, status: t.status, changedIn: round, basis: t.basis.slice(0, 4000) }
121
- : f;
125
+ if (f.status === 'open' && t)
126
+ return { ...f, status: t.status, changedIn: round, basis: t.basis.slice(0, 4000) };
127
+ // Повторно найденная закрытая/снятая находка открывается снова, а не
128
+ // теряется как дубликат по ID.
129
+ if (f.status !== 'open' && reported.some((r) => r.id === f.id))
130
+ return { ...f, status: 'open', changedIn: round, basis: 'найдена снова' };
131
+ return f;
122
132
  }),
123
- ...(parsed.success ? parsed.data.findings : [])
124
- .map((f) => ({ ...f, id: findingId(subject, f) }))
133
+ ...reported
125
134
  .filter((f) => !lastFindings.some((p) => p.id === f.id))
126
135
  .map((f) => ({
127
136
  id: f.id,
@@ -157,11 +166,14 @@ export async function technicalReview(engine, policy, adapters, input) {
157
166
  };
158
167
  // Сохраняемые представления маскируются полным окружением вызова: сырой
159
168
  // структурированный ответ адаптера может нести значение секрета профиля.
160
- await writeFile(record.artifact, JSON.stringify(redactDeep({
161
- response: parsed.success ? parsed.data : null,
162
- issues,
163
- inspection: response.inspection ?? null,
164
- }, execution.redact), null, 2));
169
+ const artifact = redactDeep({ response: parsed.success ? parsed.data : null, issues, inspection: null }, execution.redact);
170
+ // Inspection маскируется по полям: служебные значения не текст reviewer.
171
+ await writeFile(record.artifact, JSON.stringify({
172
+ ...artifact,
173
+ inspection: response.inspection
174
+ ? redactInspection(response.inspection, execution.redact)
175
+ : null,
176
+ }, null, 2));
165
177
  // Снимок, который видел reviewer, хранится по digest: согласование этого
166
178
  // раунда делает его действующим контекстом графа.
167
179
  if (context && contextKey)
@@ -47,7 +47,7 @@ export declare function scopeRecords(c: BudgetContext, view: ExecutionView, reco
47
47
  model: string | null;
48
48
  runtimeVersion: string | null;
49
49
  startedAt: string;
50
- outcome: "error" | "active" | "returned" | "abandoned";
50
+ outcome: "error" | "active" | "abandoned" | "returned";
51
51
  promptBytes: number;
52
52
  promptDigest: string;
53
53
  usage: {
@@ -133,7 +133,7 @@ export declare function workBudgets(c: BudgetContext, view: ExecutionView, workI
133
133
  model: string | null;
134
134
  runtimeVersion: string | null;
135
135
  startedAt: string;
136
- outcome: "error" | "active" | "returned" | "abandoned";
136
+ outcome: "error" | "active" | "abandoned" | "returned";
137
137
  promptBytes: number;
138
138
  promptDigest: string;
139
139
  usage: {
@@ -227,7 +227,7 @@ export declare function callBudgets(c: BudgetContext, view: ExecutionView, meta:
227
227
  model: string | null;
228
228
  runtimeVersion: string | null;
229
229
  startedAt: string;
230
- outcome: "error" | "active" | "returned" | "abandoned";
230
+ outcome: "error" | "active" | "abandoned" | "returned";
231
231
  promptBytes: number;
232
232
  promptDigest: string;
233
233
  usage: {
@@ -10,6 +10,7 @@ export const providerRefusal = (message) => /credit balance|insufficient credit|
10
10
  const byCode = {
11
11
  GATE_FAILED: 'gate',
12
12
  REVIEW_REJECTED: 'review',
13
+ REVIEW_PROTOCOL_INVALID: 'review-protocol',
13
14
  SCOPE_VIOLATION: 'scope-violation',
14
15
  BUDGET_EXHAUSTED: 'budget',
15
16
  };
@@ -251,7 +251,7 @@ export declare class Engine {
251
251
  pauseReason?: "runtime" | "operator" | "shutdown" | "base-check" | "reconfigure" | undefined;
252
252
  pausedAt?: string | undefined;
253
253
  pauseOperation?: string | undefined;
254
- pauseFailures?: ("gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "merge" | "budget")[] | undefined;
254
+ pauseFailures?: ("gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "review-protocol" | "merge" | "budget")[] | undefined;
255
255
  waits?: {
256
256
  kind: "base-check" | "context-lock";
257
257
  detail: string;
@@ -287,7 +287,7 @@ export declare class Engine {
287
287
  pauseReason?: "runtime" | "operator" | "shutdown" | "base-check" | "reconfigure" | undefined;
288
288
  pausedAt?: string | undefined;
289
289
  pauseOperation?: string | undefined;
290
- pauseFailures?: ("gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "merge" | "budget")[] | undefined;
290
+ pauseFailures?: ("gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "review-protocol" | "merge" | "budget")[] | undefined;
291
291
  waits?: {
292
292
  kind: "base-check" | "context-lock";
293
293
  detail: string;
@@ -317,7 +317,7 @@ export declare class Engine {
317
317
  pauseReason?: "runtime" | "operator" | "shutdown" | "base-check" | "reconfigure" | undefined;
318
318
  pausedAt?: string | undefined;
319
319
  pauseOperation?: string | undefined;
320
- pauseFailures?: ("gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "merge" | "budget")[] | undefined;
320
+ pauseFailures?: ("gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "review-protocol" | "merge" | "budget")[] | undefined;
321
321
  waits?: {
322
322
  kind: "base-check" | "context-lock";
323
323
  detail: string;
@@ -492,20 +492,70 @@ export declare class Engine {
492
492
  consumer?: string | undefined;
493
493
  inspection?: {
494
494
  mode: "commands" | "diff-only";
495
- source: "codex-events" | "unavailable";
495
+ source: "codex-events" | "unavailable" | "controller-probes" | "runtime-and-controller";
496
496
  commands: {
497
497
  command: string;
498
- exitCode: number;
498
+ exitCode: number | null;
499
499
  output: string;
500
+ origins?: ({
501
+ type: "runtime";
502
+ runtime: string;
503
+ item: string | null;
504
+ } | {
505
+ type: "controller";
506
+ runId: string;
507
+ })[] | undefined;
508
+ status?: "error" | "passed" | "failed" | "cancelled" | "completed" | "timeout" | undefined;
509
+ failure?: "report" | "environment" | undefined;
510
+ gate?: string | undefined;
511
+ note?: string | undefined;
500
512
  }[];
501
513
  reason: string | null;
514
+ context?: {
515
+ attempt: string;
516
+ phase: "candidate" | "integration";
517
+ sha: string;
518
+ call: number;
519
+ } | undefined;
520
+ total?: number | undefined;
521
+ excluded?: {
522
+ runId: string;
523
+ status: string | null;
524
+ reason: "not-started" | "legacy-unconfirmed" | "foreign-scope" | "unknown-status" | "unfinished" | "abandoned";
525
+ }[] | undefined;
526
+ excludedTotal?: number | undefined;
527
+ invalid?: number | undefined;
502
528
  } | undefined;
503
529
  findings?: {
504
530
  severity: string;
505
531
  message: string;
506
532
  path?: string | null | undefined;
507
533
  line?: number | null | undefined;
534
+ id?: string | undefined;
535
+ status?: "open" | "closed" | "withdrawn" | undefined;
508
536
  }[] | undefined;
537
+ reviewRound?: {
538
+ version: 1;
539
+ scope: string;
540
+ round: number;
541
+ call: number;
542
+ calls: number;
543
+ protocol: "valid" | "invalid" | "unsafe";
544
+ expected: string[];
545
+ issues?: {
546
+ path: string;
547
+ reason: "unknown" | "missing" | "schema" | "duplicate" | "not-open" | "approved-with-blocking";
548
+ message: string;
549
+ }[] | undefined;
550
+ transitions?: {
551
+ id: string;
552
+ from: "open" | "closed" | "withdrawn";
553
+ to: "open" | "closed" | "withdrawn";
554
+ basis: string;
555
+ }[] | undefined;
556
+ spec?: string | undefined;
557
+ mode?: "legacy" | "strict" | undefined;
558
+ } | undefined;
509
559
  tests?: {
510
560
  id: string;
511
561
  status: "passed" | "failed" | "skipped";
@@ -596,12 +646,12 @@ export declare class Engine {
596
646
  }): {
597
647
  recovery?: {
598
648
  id: string;
599
- status: "stopped" | "closed" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
649
+ status: "closed" | "stopped" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
600
650
  } | undefined;
601
651
  properties?: string[] | undefined;
602
652
  workId: string;
603
653
  runId: string;
604
- kind: "gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "merge" | "budget";
654
+ kind: "gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "review-protocol" | "merge" | "budget";
605
655
  blocked: boolean;
606
656
  };
607
657
  private recoveryEvent;
@@ -619,7 +669,7 @@ export declare class Engine {
619
669
  basis: string;
620
670
  runs: string[];
621
671
  openedAt: string;
622
- status: "stopped" | "closed" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
672
+ status: "closed" | "stopped" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
623
673
  calls: number;
624
674
  history: {
625
675
  at: string;
@@ -660,7 +710,7 @@ export declare class Engine {
660
710
  basis: string;
661
711
  runs: string[];
662
712
  openedAt: string;
663
- status: "stopped" | "closed" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
713
+ status: "closed" | "stopped" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
664
714
  calls: number;
665
715
  history: {
666
716
  at: string;
@@ -700,7 +750,7 @@ export declare class Engine {
700
750
  basis: string;
701
751
  runs: string[];
702
752
  openedAt: string;
703
- status: "stopped" | "closed" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
753
+ status: "closed" | "stopped" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
704
754
  calls: number;
705
755
  history: {
706
756
  at: string;
@@ -737,7 +787,7 @@ export declare class Engine {
737
787
  basis: string;
738
788
  runs: string[];
739
789
  openedAt: string;
740
- status: "stopped" | "closed" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
790
+ status: "closed" | "stopped" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
741
791
  calls: number;
742
792
  history: {
743
793
  at: string;
@@ -1240,7 +1290,7 @@ export declare class Engine {
1240
1290
  activeRunId?: string | undefined;
1241
1291
  resultSha?: string | undefined;
1242
1292
  failure?: string | undefined;
1243
- failureKind?: "gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "merge" | "budget" | undefined;
1293
+ failureKind?: "gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "review-protocol" | "merge" | "budget" | undefined;
1244
1294
  failureFingerprint?: string | undefined;
1245
1295
  approvedAt?: string | undefined;
1246
1296
  approvedDigest?: string | undefined;
@@ -1274,7 +1324,7 @@ export declare class Engine {
1274
1324
  basis: string;
1275
1325
  runs: string[];
1276
1326
  openedAt: string;
1277
- status: "stopped" | "closed" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
1327
+ status: "closed" | "stopped" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
1278
1328
  calls: number;
1279
1329
  history: {
1280
1330
  at: string;
@@ -1310,7 +1360,7 @@ export declare class Engine {
1310
1360
  basis: string;
1311
1361
  runs: string[];
1312
1362
  openedAt: string;
1313
- status: "stopped" | "closed" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
1363
+ status: "closed" | "stopped" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
1314
1364
  calls: number;
1315
1365
  history: {
1316
1366
  at: string;
@@ -1397,7 +1447,7 @@ export declare class Engine {
1397
1447
  activeRunId?: string | undefined;
1398
1448
  resultSha?: string | undefined;
1399
1449
  failure?: string | undefined;
1400
- failureKind?: "gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "merge" | "budget" | undefined;
1450
+ failureKind?: "gate" | "unknown" | "review" | "environment" | "cancelled" | "timeout" | "provider-auth" | "stale-base" | "empty-result" | "scope-violation" | "review-protocol" | "merge" | "budget" | undefined;
1401
1451
  failureFingerprint?: string | undefined;
1402
1452
  approvedAt?: string | undefined;
1403
1453
  approvedDigest?: string | undefined;
@@ -1431,7 +1481,7 @@ export declare class Engine {
1431
1481
  basis: string;
1432
1482
  runs: string[];
1433
1483
  openedAt: string;
1434
- status: "stopped" | "closed" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
1484
+ status: "closed" | "stopped" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
1435
1485
  calls: number;
1436
1486
  history: {
1437
1487
  at: string;
@@ -1467,7 +1517,7 @@ export declare class Engine {
1467
1517
  basis: string;
1468
1518
  runs: string[];
1469
1519
  openedAt: string;
1470
- status: "stopped" | "closed" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
1520
+ status: "closed" | "stopped" | "awaiting-lead" | "analyzing" | "applying" | "retry" | "retrying" | "awaiting-user";
1471
1521
  calls: number;
1472
1522
  history: {
1473
1523
  at: string;
@@ -1,4 +1,4 @@
1
- import type { AttemptState, ContextSnapshot, WorkState } from '../contracts/index.ts';
1
+ import type { AttemptState, CodeReviewHistory, ContextSnapshot, ProtocolIssue, WorkState } from '../contracts/index.ts';
2
2
  /** Предыдущие попытки поручения с находками ревью: исполнитель адресует каждую открытую. */
3
3
  export declare function previousAttempts(attempts: AttemptState[], current: string): {
4
4
  attempt: number;
@@ -13,9 +13,29 @@ export declare function previousAttempts(attempts: AttemptState[], current: stri
13
13
  message: string;
14
14
  path?: string | null | undefined;
15
15
  line?: number | null | undefined;
16
+ id?: string | undefined;
17
+ status?: "open" | "closed" | "withdrawn" | undefined;
16
18
  }[] | undefined;
17
19
  }[];
18
20
  }[];
21
+ /** Строка-заголовок раздела открытых находок; JSON — следующей строкой (её читают fixtures). */
22
+ export declare const OPEN_FINDINGS_HEADER = "Open review findings issued by the controller";
23
+ export declare const CLOSED_FINDINGS_HEADER = "Closed or withdrawn review findings (history)";
24
+ /**
25
+ * История находок ревью кода в запросе. Reviewer получает открытые находки с
26
+ * выданными ID, severity, origin и основанием, а закрытые — как историю;
27
+ * writer — открытые находки, которые нужно устранить.
28
+ */
29
+ export declare function findingsText(history: CodeReviewHistory | undefined, review: boolean): string;
30
+ /**
31
+ * Повтор reviewer после ошибки протокола: только структурированная
32
+ * диагностика прошлого ответа и требование полного валидного вердикта.
33
+ */
34
+ export declare function protocolRetryText(retry: {
35
+ call: number;
36
+ calls: number;
37
+ issues: ProtocolIssue[];
38
+ }): string;
19
39
  /** Закреплённый контекст: вложенные файлы — содержимым, справки — названием. */
20
40
  export declare function contextText(snapshot: ContextSnapshot | undefined): string;
21
41
  /** Запрос исполнителю или reviewer: исходные критерии, область, прежние находки, контекст. */
@@ -35,4 +55,12 @@ export declare function prompt(input: {
35
55
  };
36
56
  /** Обязательный корпус и решение разбора, под которым выдан повтор. */
37
57
  notes?: string[];
58
+ /** История находок ревью кода поручения (docs/review-protocol.md). */
59
+ findings?: CodeReviewHistory;
60
+ /** Повтор reviewer после ошибки протокола того же логического ревью. */
61
+ retry?: {
62
+ call: number;
63
+ calls: number;
64
+ issues: ProtocolIssue[];
65
+ };
38
66
  }): string;