gentle-pi 3.7.0 → 4.1.0
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.
- package/README.md +155 -10
- package/assets/agents/gentle-ai-explore.md +13 -6
- package/assets/agents/gentle-ai-verify.md +27 -6
- package/assets/agents/gentle-ai-worker.md +13 -15
- package/assets/install-wizard/index.html +47 -0
- package/assets/install-wizard/wizard.css +1279 -0
- package/assets/install-wizard/wizard.js +951 -0
- package/assets/orchestrator-delegation.md +75 -169
- package/assets/orchestrator-memory.md +12 -26
- package/assets/orchestrator-prompts.md +48 -0
- package/assets/orchestrator-skills.md +1 -1
- package/assets/orchestrator-tracking.md +53 -0
- package/assets/orchestrator-verification.md +28 -0
- package/assets/orchestrator-writer.md +38 -0
- package/assets/orchestrator.md +30 -38
- package/assets/sounds/LICENSE.md +52 -0
- package/assets/sounds/attention.wav +0 -0
- package/assets/sounds/error.wav +0 -0
- package/assets/sounds/success.wav +0 -0
- package/assets/support/strict-tdd-verify.md +4 -266
- package/assets/support/strict-tdd.md +8 -360
- package/bin/engram-guard +9 -0
- package/bin/gentle-shell-install.mjs +302 -0
- package/bin/gentle-shell.mjs +956 -50
- package/contracts/review-provider-contract-mirror/provider-contract.lock.json +7 -7
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/manifest.json +2 -2
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/orchestration/pi.md +16 -4
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-capabilities.baseline.json +2 -2
- package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/generated/provider-roles.baseline.json +1 -1
- package/docs/bundled-install.md +397 -0
- package/docs/delegated-verification.md +27 -4
- package/docs/gentle-agents-activity.md +537 -0
- package/docs/gentle-shell-uninstall.md +136 -0
- package/docs/gentle-shell.md +165 -51
- package/docs/install-wizard.md +2040 -0
- package/docs/native-authority-architecture.md +3 -3
- package/docs/permission-modes.md +82 -0
- package/docs/prompt-history.md +280 -0
- package/docs/readme-reference.md +364 -231
- package/docs/render-cache-performance.md +28 -0
- package/docs/sound-notifications-proposal.md +191 -0
- package/docs/sound-notifications.md +114 -0
- package/docs/telemetry.md +1 -1
- package/docs/yolo-mode.md +86 -0
- package/extensions/child-context.ts +35 -0
- package/extensions/child-safety.ts +25 -0
- package/extensions/codegraph-tools.ts +18 -5
- package/extensions/gentle-agents.ts +1093 -326
- package/extensions/gentle-ai.ts +1636 -890
- package/extensions/gentle-herdr-activity.ts +81 -0
- package/extensions/gentle-notifications.ts +104 -0
- package/extensions/gentle-shell.ts +1619 -136
- package/extensions/gentle-stats.ts +101 -0
- package/extensions/gentle-todo.ts +126 -20
- package/extensions/history/atomic-write.ts +38 -0
- package/extensions/history/hide-prompts.ts +183 -0
- package/extensions/history/index.ts +1424 -0
- package/extensions/history/load-shared-history.ts +39 -0
- package/extensions/history/selector-helpers.ts +538 -0
- package/extensions/history/session-scan.ts +233 -0
- package/extensions/history/store.ts +1119 -0
- package/extensions/nan-provider.ts +6 -0
- package/extensions/pi-pretty.ts +39 -3
- package/extensions/quiet-tools.ts +254 -92
- package/extensions/resume-hint.ts +60 -0
- package/extensions/skill-registry.ts +191 -58
- package/extensions/startup-banner.ts +71 -33
- package/lib/agent-assets.ts +604 -0
- package/lib/agent-home.ts +10 -1
- package/lib/agent-model-resolution.ts +80 -0
- package/lib/agent-profile-pin.ts +12 -0
- package/lib/agent-profiles.ts +13 -3
- package/lib/agents-completion-delivery.ts +11 -3
- package/lib/agents-message-delivery.ts +181 -0
- package/lib/agents-messaging.ts +1 -1
- package/lib/agents-protocol.ts +99 -0
- package/lib/agents-runner.ts +180 -107
- package/lib/agents-view.ts +26 -3
- package/lib/agents-widget.ts +16 -9
- package/lib/append-system-prompt.ts +21 -0
- package/lib/auto-permission-classifier.ts +280 -0
- package/lib/auto-permission-runtime.ts +268 -0
- package/lib/background-jobs-tools.ts +202 -0
- package/lib/background-jobs.ts +253 -0
- package/lib/background-monitor.ts +154 -0
- package/lib/bounded-writer-admission.ts +220 -0
- package/lib/builtin-codemode-optout.ts +166 -0
- package/lib/card-content-policy.ts +85 -0
- package/lib/card-style-policy.ts +60 -0
- package/lib/child-context-files.ts +166 -0
- package/lib/child-package-injection.ts +62 -0
- package/lib/codemode-renderer.ts +195 -0
- package/lib/command-palette-catalog.ts +5 -10
- package/lib/command-palette.ts +25 -14
- package/lib/context-threshold.ts +26 -0
- package/lib/destructive-command-guard.ts +144 -0
- package/lib/gentle-ai-binary.ts +109 -4
- package/lib/gentle-ai-elapsed-store.ts +87 -0
- package/lib/gentle-ai-renderer.ts +196 -39
- package/lib/gentle-shell-bundled.ts +517 -0
- package/lib/gentle-shell-launcher.ts +89 -27
- package/lib/gentle-shell-resume-hint.ts +176 -0
- package/lib/gentle-shell-startup-flow.ts +54 -0
- package/lib/gentle-shell-startup-update.ts +92 -0
- package/lib/gentle-shell-uninstall.ts +840 -0
- package/lib/gentle-shell-update-panel.ts +231 -0
- package/lib/herdr-activity.ts +183 -0
- package/lib/history-capture-policy.ts +95 -0
- package/lib/inprocess-reviewer.ts +3 -0
- package/lib/jobs-sidebar-state.ts +20 -0
- package/lib/jobs-view.ts +161 -0
- package/lib/model-price-ratio.ts +83 -0
- package/lib/model-routing-authority.ts +5 -1
- package/lib/nan-provider.ts +249 -0
- package/lib/native-review-cli.ts +242 -180
- package/lib/notification-audio-native.ts +162 -0
- package/lib/notification-audio-windows.ts +399 -0
- package/lib/notification-audio.ts +332 -0
- package/lib/notification-customize.ts +241 -0
- package/lib/notification-events.ts +113 -0
- package/lib/notification-policy.ts +148 -0
- package/lib/notification-pulse-client.ts +367 -0
- package/lib/notification-pulse-protocol.ts +305 -0
- package/lib/notification-pulse-stream.ts +213 -0
- package/lib/notification-pulse-worker.ts +66 -0
- package/lib/notification-scheduler.ts +173 -0
- package/lib/notification-service.ts +202 -0
- package/lib/notification-ui.ts +87 -0
- package/lib/odd-phase-inference.ts +231 -0
- package/lib/odd-phase.ts +141 -0
- package/lib/orchestrator-alias.ts +20 -0
- package/lib/orchestrator-catalog.ts +79 -0
- package/lib/orchestrator-consultation.ts +61 -0
- package/lib/orchestrator-discovery.ts +49 -0
- package/lib/orchestrator-helper-consent.ts +122 -0
- package/lib/orchestrator-helper.ts +167 -0
- package/lib/orchestrator-message-card.ts +105 -0
- package/lib/orchestrator-presence.ts +115 -14
- package/lib/orchestrator-scope.ts +80 -0
- package/lib/orchestrator-state.ts +107 -0
- package/lib/orchestrator-tool-card.ts +280 -0
- package/lib/orchestrator-work-search.ts +218 -0
- package/lib/orchestrator-work.ts +79 -0
- package/lib/overlay-repaint.ts +26 -0
- package/lib/permission-mode-policy.ts +59 -0
- package/lib/pi-tui-keys.ts +53 -0
- package/lib/review-candidate-view-owner.ts +73 -21
- package/lib/review-candidate-view.ts +115 -27
- package/lib/review-compact-contract.ts +2 -2
- package/lib/review-host-relay.ts +7 -2
- package/lib/review-integration-v2.ts +100 -22
- package/lib/review-publication-gate.ts +1 -1
- package/lib/review-reminder-receipt.ts +48 -8
- package/lib/review-risk-assessment.ts +227 -56
- package/lib/review-sidebar-state.ts +224 -0
- package/lib/review-transaction.ts +72 -3
- package/lib/runtime-metrics-children.ts +1 -1
- package/lib/runtime-metrics-native.ts +3 -2
- package/lib/selection-engine.ts +527 -0
- package/lib/session-change-capture.ts +5 -4
- package/lib/session-changes.ts +27 -22
- package/lib/session-messaging-grants.ts +135 -0
- package/lib/session-profile-binding.ts +83 -0
- package/lib/session-profile-freeze.ts +266 -0
- package/lib/session-worktree-registry.ts +87 -9
- package/lib/shell-bar.ts +215 -30
- package/lib/shell-card.ts +287 -18
- package/lib/shell-changes-view.ts +42 -14
- package/lib/shell-changes.ts +86 -71
- package/lib/shell-prompt.ts +102 -6
- package/lib/shell-sidebar-layout.ts +83 -15
- package/lib/shell-sidebar.ts +15 -1
- package/lib/shell-todo.ts +84 -31
- package/lib/shell-usage-view.ts +9 -4
- package/lib/shell-usage.ts +70 -13
- package/lib/stats-collector.ts +381 -0
- package/lib/stats-view.ts +431 -0
- package/lib/status-timing-diagnostics.ts +201 -0
- package/lib/telemetry-trigger.ts +3 -1
- package/lib/theme-customization.ts +52 -0
- package/lib/vim-editor-adapter.ts +383 -0
- package/lib/vim-normal-engine.ts +154 -0
- package/lib/vim-operator-engine.ts +416 -0
- package/lib/vim-policy.ts +49 -0
- package/lib/vim-visual-engine.ts +107 -0
- package/lib/visual-customization-policy.ts +119 -0
- package/lib/visual-customize-view.ts +481 -0
- package/lib/visual-profiles.ts +228 -0
- package/lib/writer-surfaces.ts +162 -0
- package/lib/yolo-session-policy.ts +317 -0
- package/package.json +20 -8
- package/runtime/child-package-injection.mjs +63 -0
- package/runtime/gentle-ai-binary.mjs +109 -4
- package/runtime/gentle-shell-bundled.mjs +518 -0
- package/runtime/gentle-shell-launcher.mjs +87 -25
- package/runtime/gentle-shell-resume-hint.mjs +177 -0
- package/runtime/gentle-shell-startup-flow.mjs +55 -0
- package/runtime/gentle-shell-startup-update.mjs +93 -0
- package/runtime/gentle-shell-uninstall.mjs +841 -0
- package/runtime/gentle-shell-update-panel.mjs +232 -0
- package/runtime/native-review-cli.mjs +239 -177
- package/runtime/review-integration-v2.mjs +100 -22
- package/runtime/review-risk-assessment.mjs +225 -54
- package/runtime/status-timing-diagnostics.mjs +202 -0
- package/runtime/telemetry-trigger.mjs +3 -1
- package/scripts/bootstrap.cmd +255 -0
- package/scripts/bootstrap.sh +168 -0
- package/scripts/build-distribution.mjs +157 -0
- package/scripts/build-installer-bundles.mjs +136 -0
- package/scripts/build-runtime-modules.mjs +8 -0
- package/scripts/bundled-install.mjs +1308 -0
- package/scripts/bundled-wizard.mjs +399 -0
- package/scripts/check-types.mjs +4 -6
- package/scripts/gentle-ai-installer.mjs +83 -35
- package/scripts/install-gentle-ai.mjs +48 -1
- package/scripts/install-tui-mode-setting.mjs +10 -1
- package/scripts/install-wizard-preview.mjs +154 -0
- package/scripts/installer-downloads.mjs +648 -0
- package/scripts/installer-preflight.mjs +387 -0
- package/scripts/installer-probes.mjs +564 -0
- package/scripts/installer-runner.mjs +1102 -0
- package/scripts/installer-server.mjs +881 -0
- package/scripts/installer-windows-artifacts.json +15 -0
- package/scripts/installer-windows.mjs +752 -0
- package/scripts/main-channel.mjs +452 -0
- package/scripts/mirror-odd-routing.mjs +2 -2
- package/scripts/npm-pack-result.mjs +31 -0
- package/scripts/render-cache-performance-worker.mjs +205 -0
- package/scripts/render-cache-performance.mjs +115 -0
- package/scripts/run-test-suite.mjs +90 -0
- package/scripts/test-installer-acceptance.sh +161 -0
- package/scripts/test-packed-runner.mjs +54 -19
- package/scripts/types-baseline.json +2 -92
- package/scripts/verify-package-files.mjs +91 -38
- package/skills/branch-pr/SKILL.md +24 -52
- package/skills/chained-pr/SKILL.md +31 -15
- package/skills/chained-pr/references/chaining-details.md +31 -20
- package/skills/gentle-ai/SKILL.md +16 -21
- package/skills/issue-creation/SKILL.md +8 -2
- package/skills/issue-creation/references/delegated-workflow-actions.md +19 -0
- package/skills/work-unit-commits/SKILL.md +4 -3
- package/tests/agent-home.test.ts +56 -3
- package/tests/agent-model-resolution.test.ts +113 -0
- package/tests/agent-profiles.test.ts +30 -0
- package/tests/agent-risk-escalation.test.ts +123 -0
- package/tests/agents-completion-delivery.test.ts +17 -0
- package/tests/agents-fake-child.ts +2 -2
- package/tests/agents-message-delivery.test.ts +106 -0
- package/tests/agents-protocol.test.ts +97 -0
- package/tests/agents-queries.test.ts +9 -9
- package/tests/agents-runner-process.test.ts +31 -0
- package/tests/agents-runner.test.ts +467 -93
- package/tests/agents-view-thread-identity.test.ts +169 -0
- package/tests/agents-view.test.ts +8 -2
- package/tests/agents-widget.test.ts +154 -15
- package/tests/append-system-prompt-route.test.ts +160 -0
- package/tests/append-system-prompt.test.ts +46 -0
- package/tests/artifact-language.test.ts +19 -213
- package/tests/ask-user-question.test.ts +44 -1
- package/tests/asset-installation-runtime.test.ts +5 -16
- package/tests/auto-mode-invariants.test.ts +258 -0
- package/tests/auto-mode-sdk.test.ts +57 -0
- package/tests/auto-mode.test.ts +49 -0
- package/tests/auto-permission-classifier.test.ts +283 -0
- package/tests/auto-permission-runtime.test.ts +196 -0
- package/tests/autonomous-guard.test.ts +69 -1
- package/tests/background-cache-warming.test.ts +2 -1
- package/tests/background-jobs.test.ts +227 -0
- package/tests/background-monitor.test.ts +195 -0
- package/tests/background-subagents-default-mode.test.ts +28 -5
- package/tests/bounded-stop-contract.test.ts +85 -0
- package/tests/bounded-writer-admission.test.ts +146 -0
- package/tests/branch-pr-skill.test.ts +43 -0
- package/tests/bridge-wake-lifecycle.test.ts +129 -0
- package/tests/bridge-wake-rendering.test.ts +56 -0
- package/tests/build-distribution.test.ts +269 -0
- package/tests/builtin-codemode-optout.test.ts +242 -0
- package/tests/bundled-install.test.ts +1319 -0
- package/tests/bundled-wizard.test.ts +505 -0
- package/tests/card-content-policy.test.ts +68 -0
- package/tests/card-style-policy.test.ts +87 -0
- package/tests/chained-pr-skill.test.ts +124 -0
- package/tests/child-codegraph-bootstrap.test.ts +74 -0
- package/tests/child-context-files.test.ts +255 -0
- package/tests/child-package-entrypoints.test.ts +65 -0
- package/tests/child-package-injection.test.ts +74 -0
- package/tests/child-safety.test.ts +94 -0
- package/tests/child-web-package.test.ts +224 -0
- package/tests/codegraph-tools.test.ts +35 -0
- package/tests/codemode-rendering.test.ts +596 -0
- package/tests/command-palette.test.ts +43 -7
- package/tests/context-threshold.test.ts +31 -0
- package/tests/delegate-for-reason-contract.test.ts +327 -0
- package/tests/delegated-key-learnings-contract.test.ts +3 -78
- package/tests/destructive-command-guard.test.ts +84 -0
- package/tests/devbinary/native-review-parity.devtest.ts +171 -3
- package/tests/devbinary/non-git-subagent-bootstrap.devtest.ts +193 -0
- package/tests/devbinary/pi-host-relay.devtest.ts +173 -3
- package/tests/engram-safety.test.ts +288 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +7 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +3 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T08-00-00-000Z_ddd.jsonl +2 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/2026-09-30T09-00-00-000Z_eee.jsonl +3 -0
- package/tests/fixtures/stats/sessions/--work-alpha--/run-1/session.jsonl +2 -0
- package/tests/fixtures/stats/sessions/--work-beta--/2026-09-01T12-00-00-000Z_ccc.jsonl +2 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-28T10-00-00-000Z_aaa.jsonl +2 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-alpha--/2026-09-29T23-00-00-000Z_bbb.jsonl +4 -0
- package/tests/fixtures/stats/user-pi/sessions/--work-gamma--/2026-09-20T09-00-00-000Z_fff.jsonl +3 -0
- package/tests/generic-agent-tools.test.ts +69 -0
- package/tests/gentle-agents.test.ts +2804 -346
- package/tests/gentle-ai-binary-isolation.test.ts +135 -0
- package/tests/gentle-ai-binary.test.ts +21 -4
- package/tests/gentle-ai-child-guards.test.ts +202 -0
- package/tests/gentle-ai-dev-binary-surfacing.test.ts +125 -15
- package/tests/gentle-ai-elapsed-store.test.ts +68 -0
- package/tests/gentle-ai-installer.test.ts +566 -62
- package/tests/gentle-ai-prompt-model-routing.test.ts +123 -0
- package/tests/gentle-ai-renderer.test.ts +493 -14
- package/tests/gentle-ai.test.ts +1427 -236
- package/tests/gentle-card-text.ts +2 -1
- package/tests/gentle-herdr-activity.test.ts +100 -0
- package/tests/gentle-notifications.test.ts +427 -0
- package/tests/gentle-shell-bin.test.ts +896 -115
- package/tests/gentle-shell-bundled.test.ts +1002 -0
- package/tests/gentle-shell-launcher.test.ts +333 -65
- package/tests/gentle-shell-resume-hint.test.ts +270 -0
- package/tests/gentle-shell-startup-flow.test.ts +75 -0
- package/tests/gentle-shell-startup-update.test.ts +85 -0
- package/tests/gentle-shell-uninstall.test.ts +978 -0
- package/tests/gentle-shell-update-panel.test.ts +158 -0
- package/tests/gentle-shell.test.ts +4216 -119
- package/tests/gentle-stats.test.ts +152 -0
- package/tests/gentle-theme.test.ts +4 -1
- package/tests/gentle-todo.test.ts +333 -10
- package/tests/herdr-activity.test.ts +243 -0
- package/tests/history-agent-home.test.ts +81 -0
- package/tests/history-atomic-write.test.ts +57 -0
- package/tests/history-capture-policy.test.ts +102 -0
- package/tests/history-child-guard.test.ts +70 -0
- package/tests/history-command-registration.test.ts +164 -0
- package/tests/history-dedupe-entries.test.ts +123 -0
- package/tests/history-delete-backfill.test.ts +190 -0
- package/tests/history-delete-confirm.test.ts +460 -0
- package/tests/history-dispatch.test.ts +180 -0
- package/tests/history-drain-hidden.test.ts +110 -0
- package/tests/history-drain-order.test.ts +98 -0
- package/tests/history-expanded-globals.test.ts +62 -0
- package/tests/history-gc.test.ts +832 -0
- package/tests/history-header-layout.test.ts +265 -0
- package/tests/history-hide-prompts.test.ts +275 -0
- package/tests/history-lazy-windowing.test.ts +508 -0
- package/tests/history-legacy-migrate-v2.test.ts +297 -0
- package/tests/history-load-shared-history.test.ts +53 -0
- package/tests/history-max-results-cap.test.ts +76 -0
- package/tests/history-multi-reader.test.ts +203 -0
- package/tests/history-off-path.test.ts +170 -0
- package/tests/history-openflow-integration.test.ts +173 -0
- package/tests/history-overlay-margin.test.ts +326 -0
- package/tests/history-preview-layout.test.ts +93 -0
- package/tests/history-registry.test.ts +143 -0
- package/tests/history-scope-delete.test.ts +411 -0
- package/tests/history-search-caret-keys.test.ts +142 -0
- package/tests/history-seed-bootstrap.test.ts +170 -0
- package/tests/history-seed-regen.test.ts +129 -0
- package/tests/history-selector-windowing.test.ts +94 -0
- package/tests/history-session-scan-directory.test.ts +87 -0
- package/tests/history-session-scan-extract.test.ts +583 -0
- package/tests/history-session-writer.test.ts +351 -0
- package/tests/history-store-paths.test.ts +79 -0
- package/tests/history-tombstone-exact.test.ts +139 -0
- package/tests/history-wheel-mouse.test.ts +242 -0
- package/tests/inprocess-reviewer.test.ts +49 -19
- package/tests/install-gentle-ai-failure.test.ts +69 -0
- package/tests/install-tui-mode-setting.test.ts +15 -0
- package/tests/install-wizard.test.ts +1223 -0
- package/tests/installer-bundles.test.ts +122 -0
- package/tests/installer-posix-bootstrap.test.ts +1201 -0
- package/tests/installer-preflight.test.ts +750 -0
- package/tests/installer-probes.test.ts +1106 -0
- package/tests/installer-runner.test.ts +2158 -0
- package/tests/installer-server.test.ts +1567 -0
- package/tests/installer-windows-bootstrap.test.ts +2410 -0
- package/tests/issue-creation-skill.test.ts +61 -0
- package/tests/jobs-view.test.ts +160 -0
- package/tests/main-channel-upgrade.test.ts +389 -0
- package/tests/main-channel.test.ts +344 -0
- package/tests/maintainer/provider-relay.maintest.ts +13 -12
- package/tests/model-price-ratio.test.ts +116 -0
- package/tests/model-profiles-preservation.test.ts +153 -0
- package/tests/model-routing-authority.test.ts +16 -0
- package/tests/model-routing-package.test.ts +10 -0
- package/tests/nan-provider-runtime.test.ts +156 -0
- package/tests/nan-provider.test.ts +481 -0
- package/tests/native-binary-gate.test.ts +2 -0
- package/tests/native-review-capability-contract.test.ts +13 -1
- package/tests/native-review-cli.test.ts +239 -118
- package/tests/native-review-consent.test.ts +2 -2
- package/tests/native-review-parity-runtime.test.ts +101 -4
- package/tests/native-review-parity.test.ts +12 -48
- package/tests/native-risk-evidence-parity.test.ts +21 -0
- package/tests/no-self-pause-contract.test.ts +87 -0
- package/tests/notification-audio-native.test.ts +281 -0
- package/tests/notification-audio-windows.test.ts +581 -0
- package/tests/notification-audio.test.ts +548 -0
- package/tests/notification-customize.test.ts +655 -0
- package/tests/notification-events.test.ts +115 -0
- package/tests/notification-policy.test.ts +201 -0
- package/tests/notification-pulse-client.test.ts +356 -0
- package/tests/notification-pulse-protocol.test.ts +213 -0
- package/tests/notification-pulse-stream.test.ts +320 -0
- package/tests/notification-scheduler.test.ts +258 -0
- package/tests/notification-ui.test.ts +157 -0
- package/tests/npm-pack-result.test.ts +41 -0
- package/tests/odd-integration.test.ts +76 -0
- package/tests/odd-phase-inference.test.ts +213 -0
- package/tests/odd-phase-loader.test.ts +253 -0
- package/tests/odd-phase.test.ts +307 -0
- package/tests/odd-routing-canonical-ratchet.test.ts +60 -14
- package/tests/odd-routing-contract.test.ts +158 -50
- package/tests/orchestrator-budget.test.ts +43 -45
- package/tests/orchestrator-catalog.test.ts +146 -0
- package/tests/orchestrator-consultation-sdk.test.ts +614 -0
- package/tests/orchestrator-consultation.test.ts +111 -0
- package/tests/orchestrator-discovery.test.ts +241 -0
- package/tests/orchestrator-helper-consent.test.ts +171 -0
- package/tests/orchestrator-helper.test.ts +297 -0
- package/tests/orchestrator-message-card.test.ts +190 -0
- package/tests/orchestrator-presence.test.ts +23 -0
- package/tests/orchestrator-rdd-ownership.test.ts +8 -7
- package/tests/orchestrator-scope.test.ts +107 -0
- package/tests/orchestrator-state.test.ts +114 -0
- package/tests/orchestrator-status-publication-contract.test.ts +34 -0
- package/tests/orchestrator-tool-card.test.ts +398 -0
- package/tests/orchestrator-work-search.test.ts +318 -0
- package/tests/orchestrator-work.test.ts +147 -0
- package/tests/overlay-repaint.test.ts +74 -0
- package/tests/package-manifest.test.ts +344 -123
- package/tests/packed-runner-owned-path.test.ts +80 -0
- package/tests/parallel-reason-contract.test.ts +21 -0
- package/tests/parallel-writer-admission.test.ts +210 -0
- package/tests/permission-mode-policy.test.ts +194 -0
- package/tests/persona-single-channel.test.ts +10 -18
- package/tests/pi-pretty.test.ts +56 -0
- package/tests/provider-defect-handoff.test.ts +7 -14
- package/tests/quiet-bash-runtime.test.ts +76 -0
- package/tests/quiet-tool-rendering.test.ts +569 -187
- package/tests/rdd-aware-verification-contract.test.ts +103 -40
- package/tests/rdd-status-line.test.ts +9 -4
- package/tests/render-cache-performance.test.ts +48 -0
- package/tests/resume-hint-extension.test.ts +122 -0
- package/tests/review-agent-end-preflight.test.ts +237 -21
- package/tests/review-candidate-owner-retry.test.ts +22 -1
- package/tests/review-candidate-view.test.ts +399 -12
- package/tests/review-contract-prompt.test.ts +138 -44
- package/tests/review-controller-lock-status.test.ts +0 -1
- package/tests/review-controller-native-recovery.test.ts +327 -17
- package/tests/review-controller-native-routing.test.ts +866 -6
- package/tests/review-controller-workspace-root.test.ts +206 -6
- package/tests/review-controller.test.ts +2 -2
- package/tests/review-correction-lifecycle.test.ts +2 -1
- package/tests/review-gate.test.ts +7 -4
- package/tests/review-graph-schema.test.ts +2 -2
- package/tests/review-host-relay-routing.test.ts +342 -4
- package/tests/review-host-relay.test.ts +49 -2
- package/tests/review-integration-v2-forward.test.ts +221 -1
- package/tests/review-json-arguments.test.ts +167 -0
- package/tests/review-last-event-closure.test.ts +157 -8
- package/tests/review-ledger-contract.test.ts +14 -37
- package/tests/review-policy-judgment-day.test.ts +1 -1
- package/tests/review-policy-ordinary.test.ts +2 -2
- package/tests/review-relay-transport-agent.test.ts +66 -1
- package/tests/review-reminder-receipt.test.ts +47 -1
- package/tests/review-risk-assessment.test.ts +594 -26
- package/tests/review-session-standing-permission-controller.test.ts +16 -17
- package/tests/review-session-standing-permission-ipc.test.ts +6 -5
- package/tests/review-sidebar-state.test.ts +402 -0
- package/tests/review-test-fixtures.ts +7 -1
- package/tests/review-transaction.test.ts +18 -1
- package/tests/run-test-suite.test.ts +202 -0
- package/tests/runtime-harness.mjs +186 -800
- package/tests/runtime-metrics-children.test.ts +16 -23
- package/tests/runtime-metrics-extension.test.ts +1 -1
- package/tests/runtime-metrics-native.test.ts +31 -1
- package/tests/selection-engine.test.ts +451 -0
- package/tests/session-change-capture.test.ts +10 -10
- package/tests/session-changes-shell.test.ts +242 -48
- package/tests/session-changes.test.ts +17 -24
- package/tests/session-messaging-grants.test.ts +255 -0
- package/tests/session-profile-binding.test.ts +163 -0
- package/tests/session-profile-freeze.test.ts +381 -0
- package/tests/session-subject-routing-contract.test.ts +34 -0
- package/tests/session-worktree-registry.test.ts +134 -2
- package/tests/shell-bar.test.ts +422 -1
- package/tests/shell-card.test.ts +353 -1
- package/tests/shell-changes-view.test.ts +135 -32
- package/tests/shell-changes.test.ts +61 -62
- package/tests/shell-prompt.test.ts +94 -2
- package/tests/shell-render-cache-runtime.test.ts +69 -0
- package/tests/shell-render-cache.test.ts +129 -0
- package/tests/shell-sidebar-layout.test.ts +351 -22
- package/tests/shell-sidebar-scroll-benchmark.test.ts +255 -0
- package/tests/shell-todo.test.ts +207 -3
- package/tests/shell-usage-view.test.ts +28 -1
- package/tests/shell-usage.test.ts +108 -0
- package/tests/short-check-routing-contract.test.ts +49 -0
- package/tests/skill-registry-watcher.test.ts +119 -0
- package/tests/skill-registry.test.ts +357 -2
- package/tests/startup-banner.test.ts +246 -4
- package/tests/startup-home-repo.test.ts +170 -0
- package/tests/stats-collector.test.ts +195 -0
- package/tests/stats-view.test.ts +202 -0
- package/tests/status-timing-diagnostics.test.ts +283 -0
- package/tests/support/orchestrator-modules.ts +19 -0
- package/tests/task-size-routing-contract.test.ts +241 -0
- package/tests/telemetry-trigger.test.ts +107 -20
- package/tests/test-strength-contract.test.ts +124 -0
- package/tests/theme-customization.test.ts +72 -0
- package/tests/verify-agent-contract.test.ts +90 -0
- package/tests/verify-first-launch-contract.test.ts +139 -0
- package/tests/verify-package-files.test.ts +56 -0
- package/tests/vim-editor-adapter-host-resolution.test.ts +37 -0
- package/tests/vim-editor-adapter.test.ts +804 -0
- package/tests/vim-normal-engine.test.ts +101 -0
- package/tests/vim-operator-engine.test.ts +215 -0
- package/tests/vim-policy.test.ts +19 -0
- package/tests/vim-visual-engine.test.ts +52 -0
- package/tests/visual-customization-policy.test.ts +139 -0
- package/tests/visual-customize-view.test.ts +696 -0
- package/tests/visual-profiles.test.ts +87 -0
- package/tests/writer-edit-surface-scope.test.ts +59 -2
- package/tests/writer-surfaces.test.ts +199 -0
- package/tests/yolo-customize.test.ts +271 -0
- package/tests/yolo-mode-runtime.test.ts +188 -0
- package/tests/yolo-mode.test.ts +289 -0
- package/tests/yolo-session-policy.test.ts +59 -0
- package/themes/Gentle.json +2 -1
- package/themes/Gentleman-Cute.json +2 -1
- package/themes/Gentleman-Sexy.json +2 -1
- package/assets/agents/sdd-apply.md +0 -159
- package/assets/agents/sdd-archive.md +0 -228
- package/assets/agents/sdd-design.md +0 -49
- package/assets/agents/sdd-explore.md +0 -48
- package/assets/agents/sdd-init.md +0 -56
- package/assets/agents/sdd-onboard.md +0 -52
- package/assets/agents/sdd-proposal.md +0 -64
- package/assets/agents/sdd-remediate.md +0 -37
- package/assets/agents/sdd-research.md +0 -49
- package/assets/agents/sdd-spec.md +0 -192
- package/assets/agents/sdd-status.md +0 -54
- package/assets/agents/sdd-tasks.md +0 -108
- package/assets/agents/sdd-verify.md +0 -124
- package/assets/chains/sdd-full.chain.md +0 -83
- package/assets/chains/sdd-plan.chain.md +0 -56
- package/assets/chains/sdd-verify.chain.md +0 -43
- package/assets/sdd-orchestrator-workflow.md +0 -319
- package/assets/support/sdd-status-contract.md +0 -77
- package/docs/assets/diagrams/sdd-cycle.svg +0 -14
- package/extensions/sdd-init.ts +0 -816
- package/lib/openspec-deltas.ts +0 -156
- package/lib/sdd-preflight.ts +0 -1066
- package/lib/sdd-research-capabilities.ts +0 -94
- package/lib/sdd-status.ts +0 -26
- package/tests/fixtures/legacy/sdd-research-v2.5.0.md +0 -54
- package/tests/fixtures/native-review-cli/v2.1.3/bind-sdd.json +0 -25
- package/tests/fixtures/v0.10.7/assets/agents/sdd-apply.md +0 -132
- package/tests/openspec-deltas.test.ts +0 -209
- package/tests/sdd-agent-tools.test.ts +0 -156
- package/tests/sdd-archive-replay.test.ts +0 -82
- package/tests/sdd-classical-continuation.test.ts +0 -74
- package/tests/sdd-execution-routing-contract.test.ts +0 -44
- package/tests/sdd-managed-runtime-settlement.test.ts +0 -155
- package/tests/sdd-native-managed-uptake.test.ts +0 -243
- package/tests/sdd-no-attempts-contract.test.ts +0 -15
- package/tests/sdd-odd-integration.test.ts +0 -33
- package/tests/sdd-optional-research.test.ts +0 -124
- package/tests/sdd-planning-routing-contract.test.ts +0 -45
- package/tests/sdd-preflight-rpc-input.test.ts +0 -125
- package/tests/sdd-preflight.test.ts +0 -541
- package/tests/sdd-research-capabilities.test.ts +0 -114
- package/tests/sdd-research-live.test.ts +0 -241
- package/tests/sdd-selection-transport.test.ts +0 -653
- package/tests/sdd-status.test.ts +0 -9
- package/tests/sdd-task-truth.test.ts +0 -43
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/README.md +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/lens.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/refuter.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/schemas/targeted-validator.schema.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/lens.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/refuter.json +0 -0
- /package/contracts/review-provider-contract-mirror/{v1.2.0 → v1.3.0}/bundle/vectors/targeted-validator.json +0 -0
|
@@ -78,8 +78,8 @@ export const REVIEW_START_STATE = {
|
|
|
78
78
|
const START_ACTIONS = ["created", "resumed", "closed", "blocked-scope-action"] ;
|
|
79
79
|
const RISK_LEVELS = ["low", "medium", "high"] ;
|
|
80
80
|
const REVIEW_LENSES = ["review-risk", "review-resilience", "review-readability", "review-reliability"] ;
|
|
81
|
-
const RISK_REASON_CODES = ["configuration_change", "empty_content", "executable_change", "executable_mode", "hot_path", "large_change", "non_executable_only", "process_boundary", "process_scan_limit", "service_token", "shell_source"] ;
|
|
82
|
-
const RISK_SIGNALS = ["auth", "update", "security", "payments", "permissions", "shell_process"] ;
|
|
81
|
+
const RISK_REASON_CODES = ["agent_escalation", "configuration_change", "dangerous_sink", "empty_content", "executable_change", "executable_mode", "hot_path", "large_change", "non_executable_only", "process_boundary", "process_scan_limit", "service_token", "shell_source"] ;
|
|
82
|
+
const RISK_SIGNALS = ["auth", "update", "security", "payments", "permissions", "shell_process", "dangerous_sink", "agent_escalation"] ;
|
|
83
83
|
// "collect" and "execute" are the v2 envelope's projection of a live
|
|
84
84
|
// transaction whose next_transition is mandatory: the root action names the
|
|
85
85
|
// transition kind instead of reading as a terminal stop.
|
|
@@ -637,6 +637,23 @@ const ESCALATION_REFUTER_OUTCOMES = ["corroborated", "refuted", "inconclusive"]
|
|
|
637
637
|
|
|
638
638
|
|
|
639
639
|
|
|
640
|
+
function decodeReviewEscalationV1(value , label ) {
|
|
641
|
+
const source = exactRecord(value, label, ["cause", "finding_ids"], ["refuter_outcomes"]);
|
|
642
|
+
const escalation = {
|
|
643
|
+
cause: enumeration(source.cause, ESCALATION_CAUSES, `${label}.cause`),
|
|
644
|
+
findingIds: stringArray(source.finding_ids, `${label}.finding_ids`),
|
|
645
|
+
};
|
|
646
|
+
if (Object.hasOwn(source, "refuter_outcomes")) escalation.refuterOutcomes = array(source.refuter_outcomes, `${label}.refuter_outcomes`, (entry, itemLabel) => {
|
|
647
|
+
const row = exactRecord(entry, itemLabel, ["finding_id", "outcome", "proof"]);
|
|
648
|
+
return {
|
|
649
|
+
findingId: nonempty(row.finding_id, `${itemLabel}.finding_id`),
|
|
650
|
+
outcome: enumeration(row.outcome, ESCALATION_REFUTER_OUTCOMES, `${itemLabel}.outcome`),
|
|
651
|
+
proof: nonempty(row.proof, `${itemLabel}.proof`),
|
|
652
|
+
};
|
|
653
|
+
});
|
|
654
|
+
return escalation;
|
|
655
|
+
}
|
|
656
|
+
|
|
640
657
|
|
|
641
658
|
|
|
642
659
|
|
|
@@ -2105,23 +2122,9 @@ export function decodeReviewStatusV3(value ) {
|
|
|
2105
2122
|
};
|
|
2106
2123
|
}
|
|
2107
2124
|
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
const source = exactRecord(body.escalation, label, ["cause", "finding_ids"], ["refuter_outcomes"]);
|
|
2112
|
-
escalation = {
|
|
2113
|
-
cause: enumeration(source.cause, ESCALATION_CAUSES, `${label}.cause`),
|
|
2114
|
-
findingIds: stringArray(source.finding_ids, `${label}.finding_ids`),
|
|
2115
|
-
};
|
|
2116
|
-
if (Object.hasOwn(source, "refuter_outcomes")) escalation.refuterOutcomes = array(source.refuter_outcomes, `${label}.refuter_outcomes`, (entry, itemLabel) => {
|
|
2117
|
-
const row = exactRecord(entry, itemLabel, ["finding_id", "outcome", "proof"]);
|
|
2118
|
-
return {
|
|
2119
|
-
findingId: nonempty(row.finding_id, `${itemLabel}.finding_id`),
|
|
2120
|
-
outcome: enumeration(row.outcome, ESCALATION_REFUTER_OUTCOMES, `${itemLabel}.outcome`),
|
|
2121
|
-
proof: nonempty(row.proof, `${itemLabel}.proof`),
|
|
2122
|
-
};
|
|
2123
|
-
});
|
|
2124
|
-
}
|
|
2125
|
+
const escalation = Object.hasOwn(body, "escalation")
|
|
2126
|
+
? decodeReviewEscalationV1(body.escalation, "status.escalation")
|
|
2127
|
+
: undefined;
|
|
2125
2128
|
|
|
2126
2129
|
// status/v7 top-level optional digest (gentle-ai v2.6.0): resolves #4066's
|
|
2127
2130
|
// closed loop where `sdd-attempt finish` named a digest status never
|
|
@@ -2584,7 +2587,11 @@ function assertReviewApprovedAcknowledgementExecuteShapeV1(execute
|
|
|
2584
2587
|
if (execute.arguments.length !== REVIEW_APPROVED_ACKNOWLEDGEMENT_ARGUMENTS.length) throw new TypeError(`acknowledgement.execute.arguments must carry exactly ${REVIEW_APPROVED_ACKNOWLEDGEMENT_ARGUMENTS.length} provider-issued arguments`);
|
|
2585
2588
|
const values = execute.arguments.map((argument, index) => { const name = REVIEW_APPROVED_ACKNOWLEDGEMENT_ARGUMENTS[index] ; if (argument.name !== name) throw new TypeError(`acknowledgement.execute.arguments[${index}].name must be ${name}`); const value = nonempty(argument.value, `acknowledgement.execute.arguments[${index}].value`); if (nonempty(argument.token, `acknowledgement.execute.arguments[${index}].token`) !== `--${name}=${value}`) throw new TypeError(`acknowledgement.execute.arguments[${index}].token must exactly match ${name}`); return value; });
|
|
2586
2589
|
if (execute.preconditions.length !== 1 || execute.preconditions[0]?.name !== "state" || execute.preconditions[0]?.value !== "approved") throw new TypeError("acknowledgement.execute.preconditions must be the single approved state precondition");
|
|
2587
|
-
|
|
2590
|
+
const tokens = execute.arguments.map((argument) => argument.token );
|
|
2591
|
+
// The exact five-argument check above validates both vectors before tuple construction.
|
|
2592
|
+
const tokenTuple = [tokens[0] , tokens[1] , tokens[2] , tokens[3] , tokens[4] ];
|
|
2593
|
+
const valueTuple = [values[0] , values[1] , values[2] , values[3] , values[4] ];
|
|
2594
|
+
return { tokens: tokenTuple, values: valueTuple, lineageId: lineage(execute.binding.lineageId, "acknowledgement.execute.binding.lineage_id"), targetIdentity: sha256(execute.binding.targetIdentity, "acknowledgement.execute.binding.target_identity"), revision: sha256(execute.binding.revision, "acknowledgement.execute.binding.revision") };
|
|
2588
2595
|
}
|
|
2589
2596
|
|
|
2590
2597
|
/**
|
|
@@ -2689,6 +2696,28 @@ const REVIEW_LAST_EVENT_CAUSAL_DISPOSITIONS = ["introduced", "behavior-activated
|
|
|
2689
2696
|
|
|
2690
2697
|
|
|
2691
2698
|
|
|
2699
|
+
|
|
2700
|
+
|
|
2701
|
+
|
|
2702
|
+
|
|
2703
|
+
|
|
2704
|
+
|
|
2705
|
+
|
|
2706
|
+
|
|
2707
|
+
|
|
2708
|
+
|
|
2709
|
+
|
|
2710
|
+
|
|
2711
|
+
|
|
2712
|
+
|
|
2713
|
+
|
|
2714
|
+
|
|
2715
|
+
|
|
2716
|
+
|
|
2717
|
+
|
|
2718
|
+
|
|
2719
|
+
|
|
2720
|
+
|
|
2692
2721
|
|
|
2693
2722
|
|
|
2694
2723
|
|
|
@@ -2836,18 +2865,67 @@ function decodeReviewLastEventReviewerResultV1(value , label )
|
|
|
2836
2865
|
};
|
|
2837
2866
|
}
|
|
2838
2867
|
|
|
2868
|
+
function decodeReviewTargetedValidatorCheckEvidenceV1(value , label ) {
|
|
2869
|
+
const check = exactRecord(value, label, ["passed", "evidence"], ["regressions"]);
|
|
2870
|
+
const regressions = Object.hasOwn(check, "regressions")
|
|
2871
|
+
? array(check.regressions, `${label}.regressions`, (entry, entryLabel) => {
|
|
2872
|
+
const row = exactRecord(entry, entryLabel, ["location", "claim", "proof_refs"], ["id"]);
|
|
2873
|
+
return {
|
|
2874
|
+
...(Object.hasOwn(row, "id") ? { id: nonempty(row.id, `${entryLabel}.id`) } : {}),
|
|
2875
|
+
location: nonempty(row.location, `${entryLabel}.location`),
|
|
2876
|
+
claim: nonempty(row.claim, `${entryLabel}.claim`),
|
|
2877
|
+
proofRefs: stringArray(row.proof_refs, `${entryLabel}.proof_refs`, { minimum: 1 }),
|
|
2878
|
+
};
|
|
2879
|
+
}) : undefined;
|
|
2880
|
+
return {
|
|
2881
|
+
passed: boolean(check.passed, `${label}.passed`),
|
|
2882
|
+
// Native admission rejects observations containing only Unicode whitespace.
|
|
2883
|
+
evidence: stringArray(check.evidence, `${label}.evidence`, { minimum: 1, pattern: /[^\p{White_Space}]/u }),
|
|
2884
|
+
...(regressions === undefined ? {} : { regressions }),
|
|
2885
|
+
};
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
function decodeReviewTargetedValidatorEvidenceV1(value , label ) {
|
|
2889
|
+
const body = exactRecord(value, label, ["targeted_validation_request_hash", "correction_target_identity", "original_criteria", "correction_regression", "follow_ups"]);
|
|
2890
|
+
return {
|
|
2891
|
+
targetedValidationRequestHash: sha256(body.targeted_validation_request_hash, `${label}.targeted_validation_request_hash`),
|
|
2892
|
+
correctionTargetIdentity: sha256(body.correction_target_identity, `${label}.correction_target_identity`),
|
|
2893
|
+
originalCriteria: decodeReviewTargetedValidatorCheckEvidenceV1(body.original_criteria, `${label}.original_criteria`),
|
|
2894
|
+
correctionRegression: decodeReviewTargetedValidatorCheckEvidenceV1(body.correction_regression, `${label}.correction_regression`),
|
|
2895
|
+
followUps: array(body.follow_ups, `${label}.follow_ups`, (entry, entryLabel) => {
|
|
2896
|
+
const row = exactRecord(entry, entryLabel, ["observation", "proof_refs"]);
|
|
2897
|
+
return { observation: nonempty(row.observation, `${entryLabel}.observation`), proofRefs: stringArray(row.proof_refs, `${entryLabel}.proof_refs`, { minimum: 1 }) };
|
|
2898
|
+
}),
|
|
2899
|
+
raw: body,
|
|
2900
|
+
};
|
|
2901
|
+
}
|
|
2902
|
+
|
|
2839
2903
|
export function decodeReviewLastEventClosureV1(value ) {
|
|
2840
|
-
const body = exactRecord(value, "last_event_closure", ["schema", "operation", "lineage_id", "state", "store_revision"], ["target_identity", "request_hash", "correction_lines", "action", "advisory_findings", "reviewer_results", "status_continuation", "acknowledgement"]);
|
|
2904
|
+
const body = exactRecord(value, "last_event_closure", ["schema", "operation", "lineage_id", "state", "store_revision"], ["target_identity", "request_hash", "correction_lines", "action", "escalation", "targeted_validator_evidence", "advisory_findings", "reviewer_results", "status_continuation", "acknowledgement"]);
|
|
2841
2905
|
if (body.schema !== REVIEW_LAST_EVENT_CLOSURE_SCHEMA) throw new TypeError(`last_event_closure.schema must be ${REVIEW_LAST_EVENT_CLOSURE_SCHEMA}`);
|
|
2842
2906
|
const operation = enumeration(body.operation, Object.values(REVIEW_LAST_EVENT_CLOSURE_OPERATION), "last_event_closure.operation") ;
|
|
2843
2907
|
const state = enumeration(body.state, REVIEW_LAST_EVENT_TERMINAL_STATES, "last_event_closure.state") ;
|
|
2908
|
+
if (Object.hasOwn(body, "targeted_validator_evidence") && (operation !== REVIEW_LAST_EVENT_CLOSURE_OPERATION.CAPTURE_VALIDATION || state !== "escalated")) {
|
|
2909
|
+
throw new TypeError("last_event_closure targeted_validator_evidence requires escalated review/capture-validation");
|
|
2910
|
+
}
|
|
2911
|
+
// Diagnostic evidence is optional for older providers and never controls terminal authority.
|
|
2912
|
+
const targetedValidatorEvidence = Object.hasOwn(body, "targeted_validator_evidence")
|
|
2913
|
+
? decodeReviewTargetedValidatorEvidenceV1(body.targeted_validator_evidence, "last_event_closure.targeted_validator_evidence")
|
|
2914
|
+
: undefined;
|
|
2915
|
+
if (Object.hasOwn(body, "escalation") && state !== "escalated") throw new TypeError("last_event_closure escalation requires escalated state");
|
|
2916
|
+
// Older native closures omit this diagnostic; its presence never grants a continuation.
|
|
2917
|
+
const escalation = Object.hasOwn(body, "escalation")
|
|
2918
|
+
? decodeReviewEscalationV1(body.escalation, "last_event_closure.escalation")
|
|
2919
|
+
: undefined;
|
|
2844
2920
|
const shared = {
|
|
2845
2921
|
schema: REVIEW_LAST_EVENT_CLOSURE_SCHEMA,
|
|
2846
2922
|
operation,
|
|
2847
2923
|
lineageId: lineage(body.lineage_id, "last_event_closure.lineage_id"),
|
|
2848
2924
|
state,
|
|
2849
2925
|
storeRevision: sha256(body.store_revision, "last_event_closure.store_revision"),
|
|
2850
|
-
|
|
2926
|
+
...(escalation === undefined ? {} : { escalation }),
|
|
2927
|
+
...(targetedValidatorEvidence === undefined ? {} : { targetedValidatorEvidence }),
|
|
2928
|
+
} ;
|
|
2851
2929
|
if (operation === REVIEW_LAST_EVENT_CLOSURE_OPERATION.CAPTURE_CORRECTION_PLAN) {
|
|
2852
2930
|
if (body.reviewer_results !== undefined) throw new TypeError("last_event_closure reviewer_results requires approved state");
|
|
2853
2931
|
if (body.action !== undefined || body.advisory_findings !== undefined || body.status_continuation !== undefined) throw new TypeError("last_event_closure correction-plan cannot carry action, advisory_findings, or status_continuation");
|
|
@@ -11,6 +11,11 @@
|
|
|
11
11
|
// prints `{"schema":"gentle-ai.review-assessment/v1","risk":"passive|medium|high",
|
|
12
12
|
// "reasons":[{"code":"…","path":"…","detail":"…"}],"changed_paths":1,
|
|
13
13
|
// "changed_lines":1,"candidate":{"kind":"current-changes|base-diff","base_ref":"…"}}`.
|
|
14
|
+
// gentle-pi#1175: the native v2 `assess.schema.json` requires only `code` on a
|
|
15
|
+
// reason (`path`/`detail` are optional) and adds `candidate.consumed`,
|
|
16
|
+
// `review_due`, `review_due_reason`, and an opaque `next_transition`. Older
|
|
17
|
+
// binaries (for example gentle-ai v3.7.0) predate those fields, so
|
|
18
|
+
// they decode as optional and stay absent rather than being defaulted.
|
|
14
19
|
// A non-zero exit or a failure envelope means the candidate could not be
|
|
15
20
|
// assessed; hosts treat that as `high`. Older binaries without the verb (or
|
|
16
21
|
// any other decode/process failure) fail closed the same way -- see
|
|
@@ -31,6 +36,41 @@ export const REVIEW_ASSESSMENT_CANDIDATE_KIND = {
|
|
|
31
36
|
} ;
|
|
32
37
|
|
|
33
38
|
|
|
39
|
+
export const REVIEW_DUE_REASON = {
|
|
40
|
+
HIGH_RISK: "high_risk",
|
|
41
|
+
SLICE_BUDGET_REACHED: "slice_budget_reached",
|
|
42
|
+
PASSIVE: "passive",
|
|
43
|
+
UNDER_BUDGET: "under_budget",
|
|
44
|
+
ALREADY_REVIEWED: "already_reviewed",
|
|
45
|
+
} ;
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
export const REVIEW_ASSESSMENT_NEXT_TRANSITION_OPERATION = "review.status" ;
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* The native, literally runnable `review status ... --next-transition`
|
|
71
|
+
* preflight continuation. Carried verbatim as an opaque value: hosts never
|
|
72
|
+
* rebuild, reorder, or synthesize it.
|
|
73
|
+
*/
|
|
34
74
|
|
|
35
75
|
|
|
36
76
|
|
|
@@ -55,25 +95,104 @@ function isRecord(value ) {
|
|
|
55
95
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
56
96
|
}
|
|
57
97
|
|
|
98
|
+
function isNonEmptyString(value ) {
|
|
99
|
+
return typeof value === "string" && value.length > 0;
|
|
100
|
+
}
|
|
101
|
+
|
|
58
102
|
function decodeReason(value ) {
|
|
59
103
|
if (!isRecord(value)) throw new TypeError("review assessment reason must be an object");
|
|
60
104
|
const { code, path, detail } = value;
|
|
61
|
-
if (
|
|
62
|
-
if (
|
|
63
|
-
if (
|
|
64
|
-
|
|
105
|
+
if (!isNonEmptyString(code)) throw new TypeError("review assessment reason.code must be a non-empty string");
|
|
106
|
+
if (path !== undefined && !isNonEmptyString(path)) throw new TypeError("review assessment reason.path must be a non-empty string when present");
|
|
107
|
+
if (detail !== undefined && !isNonEmptyString(detail)) throw new TypeError("review assessment reason.detail must be a non-empty string when present");
|
|
108
|
+
// Absent path/detail stay absent: never synthesized (gentle-pi#1175).
|
|
109
|
+
return Object.freeze({
|
|
110
|
+
code,
|
|
111
|
+
...(path === undefined ? {} : { path: path }),
|
|
112
|
+
...(detail === undefined ? {} : { detail: detail }),
|
|
113
|
+
});
|
|
65
114
|
}
|
|
66
115
|
|
|
67
116
|
function decodeCandidate(value ) {
|
|
68
117
|
if (!isRecord(value)) throw new TypeError("review assessment candidate must be an object");
|
|
69
|
-
const { kind, base_ref: baseRef } = value;
|
|
118
|
+
const { kind, base_ref: baseRef, consumed } = value;
|
|
70
119
|
if (kind !== REVIEW_ASSESSMENT_CANDIDATE_KIND.CURRENT_CHANGES && kind !== REVIEW_ASSESSMENT_CANDIDATE_KIND.BASE_DIFF) {
|
|
71
120
|
throw new TypeError("review assessment candidate.kind must be current-changes or base-diff");
|
|
72
121
|
}
|
|
73
|
-
if (baseRef !== undefined && (
|
|
122
|
+
if (baseRef !== undefined && !isNonEmptyString(baseRef)) {
|
|
74
123
|
throw new TypeError("review assessment candidate.base_ref must be a non-empty string when present");
|
|
75
124
|
}
|
|
76
|
-
|
|
125
|
+
if (consumed !== undefined && typeof consumed !== "boolean") {
|
|
126
|
+
throw new TypeError("review assessment candidate.consumed must be a boolean when present");
|
|
127
|
+
}
|
|
128
|
+
// An older binary omits consumed; it stays absent, never defaulted.
|
|
129
|
+
return Object.freeze({ kind, baseRef: baseRef , ...(consumed === undefined ? {} : { consumed: consumed }) });
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function isReviewDueReason(value ) {
|
|
133
|
+
return Object.values(REVIEW_DUE_REASON).includes(value );
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// The native schema fixes review_due by reason: due for high_risk and
|
|
137
|
+
// slice_budget_reached, not due for passive, under_budget, and
|
|
138
|
+
// already_reviewed (gentle-pi#1175).
|
|
139
|
+
const DUE_REVIEW_REASONS = [REVIEW_DUE_REASON.HIGH_RISK, REVIEW_DUE_REASON.SLICE_BUDGET_REACHED];
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Rejects a review_due/review_due_reason/consumed combination the native
|
|
143
|
+
* schema can never produce. A consumed candidate must report
|
|
144
|
+
* `already_reviewed`, but that reason can also describe an acknowledged
|
|
145
|
+
* committed predecessor followed by a passive delta (#1954). It does not
|
|
146
|
+
* prove this exact candidate was consumed; preserve native's explicit false.
|
|
147
|
+
* Native v2 requires consumed, so missing evidence with already_reviewed is
|
|
148
|
+
* still rejected. Envelopes without the pair (older binaries) are unchecked.
|
|
149
|
+
*/
|
|
150
|
+
function validateReviewDueConsistency(reviewDue , reviewDueReason , candidate ) {
|
|
151
|
+
if (reviewDue !== DUE_REVIEW_REASONS.includes(reviewDueReason)) {
|
|
152
|
+
throw new TypeError(`review assessment review_due ${reviewDue} contradicts review_due_reason ${reviewDueReason}`);
|
|
153
|
+
}
|
|
154
|
+
const alreadyReviewed = reviewDueReason === REVIEW_DUE_REASON.ALREADY_REVIEWED;
|
|
155
|
+
if (candidate.consumed === true && !alreadyReviewed) {
|
|
156
|
+
throw new TypeError("review assessment candidate.consumed true requires review_due_reason already_reviewed");
|
|
157
|
+
}
|
|
158
|
+
if (alreadyReviewed && candidate.consumed === undefined) {
|
|
159
|
+
throw new TypeError("review assessment review_due_reason already_reviewed requires explicit candidate.consumed evidence");
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function hasOnlyKeys(value , allowed ) {
|
|
164
|
+
return Object.keys(value).every((key) => allowed.includes(key));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function validateNextTransitionArgument(value ) {
|
|
168
|
+
if (!isRecord(value) || !hasOnlyKeys(value, ["name", "value", "token"])) {
|
|
169
|
+
throw new TypeError("review assessment next_transition argument must be an object with only name, value, and token");
|
|
170
|
+
}
|
|
171
|
+
if (!isNonEmptyString(value.name)) throw new TypeError("review assessment next_transition argument name must be a non-empty string");
|
|
172
|
+
if (typeof value.value !== "string") throw new TypeError("review assessment next_transition argument value must be a string");
|
|
173
|
+
if (value.token !== undefined && !isNonEmptyString(value.token)) {
|
|
174
|
+
throw new TypeError("review assessment next_transition argument token must be a non-empty string when present");
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Validates `next_transition` exactly as the native schema declares it and
|
|
180
|
+
* returns the native value itself, frozen -- validated, never rebuilt,
|
|
181
|
+
* reordered, or synthesized (gentle-pi#1175).
|
|
182
|
+
*/
|
|
183
|
+
function decodeNextTransition(value ) {
|
|
184
|
+
if (!isRecord(value) || !hasOnlyKeys(value, ["operation", "command", "arguments"])) {
|
|
185
|
+
throw new TypeError("review assessment next_transition must be an object with only operation, command, and arguments");
|
|
186
|
+
}
|
|
187
|
+
if (value.operation !== REVIEW_ASSESSMENT_NEXT_TRANSITION_OPERATION) {
|
|
188
|
+
throw new TypeError(`review assessment next_transition.operation must be ${REVIEW_ASSESSMENT_NEXT_TRANSITION_OPERATION}`);
|
|
189
|
+
}
|
|
190
|
+
if (!isNonEmptyString(value.command)) throw new TypeError("review assessment next_transition.command must be a non-empty string");
|
|
191
|
+
if (!Array.isArray(value.arguments)) throw new TypeError("review assessment next_transition.arguments must be an array");
|
|
192
|
+
for (const argument of value.arguments) validateNextTransitionArgument(argument);
|
|
193
|
+
for (const argument of value.arguments) Object.freeze(argument);
|
|
194
|
+
Object.freeze(value.arguments);
|
|
195
|
+
return Object.freeze(value) ;
|
|
77
196
|
}
|
|
78
197
|
|
|
79
198
|
/**
|
|
@@ -82,24 +201,55 @@ function decodeCandidate(value ) {
|
|
|
82
201
|
* native review CLI wrapper turns a thrown error here into the same
|
|
83
202
|
* schema-incompatible failure it already produces for every other decoded
|
|
84
203
|
* native response.
|
|
204
|
+
*
|
|
205
|
+
* `review_due` and `review_due_reason` were added together natively: both
|
|
206
|
+
* absent (an older binary) or both present are accepted; only one of them is
|
|
207
|
+
* rejected. When present, the pair must agree with each other and with
|
|
208
|
+
* `candidate.consumed` (see `validateReviewDueConsistency`).
|
|
209
|
+
* `next_transition` is accepted only alongside `review_due: true`.
|
|
210
|
+
* Unknown extra top-level fields are ignored and never projected, so a newer
|
|
211
|
+
* binary stays decodable (gentle-pi#1175).
|
|
85
212
|
*/
|
|
86
213
|
export function decodeReviewAssessmentV1(value ) {
|
|
87
214
|
if (!isRecord(value)) throw new TypeError("review assessment must be an object");
|
|
88
215
|
if (value.schema !== REVIEW_ASSESSMENT_SCHEMA) throw new TypeError(`review assessment schema must be ${REVIEW_ASSESSMENT_SCHEMA}`);
|
|
89
|
-
const {
|
|
216
|
+
const {
|
|
217
|
+
risk,
|
|
218
|
+
reasons,
|
|
219
|
+
changed_paths: changedPaths,
|
|
220
|
+
changed_lines: changedLines,
|
|
221
|
+
candidate,
|
|
222
|
+
review_due: reviewDue,
|
|
223
|
+
review_due_reason: reviewDueReason,
|
|
224
|
+
next_transition: nextTransition,
|
|
225
|
+
} = value;
|
|
90
226
|
if (risk !== REVIEW_ASSESSMENT_RISK.PASSIVE && risk !== REVIEW_ASSESSMENT_RISK.MEDIUM && risk !== REVIEW_ASSESSMENT_RISK.HIGH) {
|
|
91
227
|
throw new TypeError("review assessment risk must be passive, medium, or high");
|
|
92
228
|
}
|
|
93
229
|
if (!Array.isArray(reasons)) throw new TypeError("review assessment reasons must be an array");
|
|
94
230
|
if (!Number.isSafeInteger(changedPaths) || (changedPaths ) < 0) throw new TypeError("review assessment changed_paths must be a non-negative integer");
|
|
95
231
|
if (!Number.isSafeInteger(changedLines) || (changedLines ) < 0) throw new TypeError("review assessment changed_lines must be a non-negative integer");
|
|
232
|
+
if ((reviewDue === undefined) !== (reviewDueReason === undefined)) {
|
|
233
|
+
throw new TypeError("review assessment review_due and review_due_reason must be both present or both absent");
|
|
234
|
+
}
|
|
235
|
+
if (reviewDue !== undefined && typeof reviewDue !== "boolean") throw new TypeError("review assessment review_due must be a boolean when present");
|
|
236
|
+
if (reviewDueReason !== undefined && !isReviewDueReason(reviewDueReason)) {
|
|
237
|
+
throw new TypeError(`review assessment review_due_reason must be one of ${Object.values(REVIEW_DUE_REASON).join(", ")}`);
|
|
238
|
+
}
|
|
239
|
+
if (nextTransition !== undefined && reviewDue !== true) {
|
|
240
|
+
throw new TypeError("review assessment next_transition is only valid when review_due is true");
|
|
241
|
+
}
|
|
242
|
+
const decodedCandidate = decodeCandidate(candidate);
|
|
243
|
+
if (reviewDue !== undefined) validateReviewDueConsistency(reviewDue , reviewDueReason , decodedCandidate);
|
|
96
244
|
return Object.freeze({
|
|
97
245
|
schema: REVIEW_ASSESSMENT_SCHEMA,
|
|
98
246
|
risk,
|
|
99
247
|
reasons: Object.freeze(reasons.map(decodeReason)),
|
|
100
248
|
changedPaths: changedPaths ,
|
|
101
249
|
changedLines: changedLines ,
|
|
102
|
-
candidate:
|
|
250
|
+
candidate: decodedCandidate,
|
|
251
|
+
...(reviewDue === undefined ? {} : { reviewDue: reviewDue , reviewDueReason: reviewDueReason }),
|
|
252
|
+
...(nextTransition === undefined ? {} : { nextTransition: decodeNextTransition(nextTransition) }),
|
|
103
253
|
});
|
|
104
254
|
}
|
|
105
255
|
|
|
@@ -115,6 +265,53 @@ export const VERIFICATION_TIER = {
|
|
|
115
265
|
} ;
|
|
116
266
|
|
|
117
267
|
|
|
268
|
+
// ---------------------------------------------------------------------------
|
|
269
|
+
// Agent-raised risk (gentle-shell#1494). The agent that made the change may
|
|
270
|
+
// raise its risk to high by citing one item of the high-risk list in the
|
|
271
|
+
// always-on Task Size section; it can never lower a tier. Lowering stays with
|
|
272
|
+
// the deterministic native assessment.
|
|
273
|
+
// ---------------------------------------------------------------------------
|
|
274
|
+
|
|
275
|
+
export const HIGH_RISK_ITEMS = Object.freeze({
|
|
276
|
+
1: "data or irreversible effects",
|
|
277
|
+
2: "security",
|
|
278
|
+
3: "changing or removing contracts others already consume",
|
|
279
|
+
4: "concurrency",
|
|
280
|
+
5: "delivery or environment",
|
|
281
|
+
6: "no test would catch a regression",
|
|
282
|
+
} );
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
export const AGENT_RISK_ESCALATION_REASON_MAX = 500;
|
|
291
|
+
|
|
292
|
+
export function decodeAgentRiskEscalation(value ) {
|
|
293
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
294
|
+
throw new Error("escalate must be an object with item and reason");
|
|
295
|
+
}
|
|
296
|
+
const record = value ;
|
|
297
|
+
const unexpected = Object.keys(record).find((key) => key !== "item" && key !== "reason");
|
|
298
|
+
if (unexpected !== undefined) throw new Error(`escalate does not accept ${unexpected}`);
|
|
299
|
+
const { item, reason } = record;
|
|
300
|
+
if (typeof item !== "number" || !Number.isInteger(item) || !(item in HIGH_RISK_ITEMS)) {
|
|
301
|
+
throw new Error("escalate item must be an integer from 1 to 6 naming a high-risk item");
|
|
302
|
+
}
|
|
303
|
+
if (typeof reason !== "string" || reason.trim() === "" || reason.length > AGENT_RISK_ESCALATION_REASON_MAX) {
|
|
304
|
+
throw new Error(`escalate reason must be a non-empty string of at most ${AGENT_RISK_ESCALATION_REASON_MAX} characters`);
|
|
305
|
+
}
|
|
306
|
+
return Object.freeze({ item: item , reason });
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Raises passive or medium to high when the agent escalated; never lowers. */
|
|
310
|
+
export function escalatedRisk(risk , escalation ) {
|
|
311
|
+
if (escalation === undefined) return risk;
|
|
312
|
+
return risk === VERIFICATION_TIER.PASSIVE || risk === VERIFICATION_TIER.MEDIUM ? VERIFICATION_TIER.HIGH : risk;
|
|
313
|
+
}
|
|
314
|
+
|
|
118
315
|
export const RDD_LINE = {
|
|
119
316
|
ON: "on",
|
|
120
317
|
OFF: "off",
|
|
@@ -219,59 +416,33 @@ function nonClosedOutcomeClause(outcome ) {
|
|
|
219
416
|
}
|
|
220
417
|
|
|
221
418
|
/**
|
|
222
|
-
* Computes who verifies a delegated writer's change
|
|
223
|
-
*
|
|
419
|
+
* Computes who verifies a delegated writer's change. Verification follows the
|
|
420
|
+
* native risk tier whatever the RDD line and native review outcome
|
|
421
|
+
* (verify-always-rdd-high S1, superseding the gentle-pi#662/#668 on-path): the
|
|
422
|
+
* native review is an additional outside view and never replaces or skips the
|
|
423
|
+
* tier's verification. `nativeReviewOutcome` only shapes the reason text.
|
|
224
424
|
*
|
|
225
|
-
* - `
|
|
226
|
-
*
|
|
227
|
-
*
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
231
|
-
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
* never lowers a tier relative to `off`; `nativeReviewOutcome` is ignored
|
|
236
|
-
* entirely on these lines):
|
|
237
|
-
* - `passive`: structural readback by the parent only; no verifier, no
|
|
238
|
-
* tests.
|
|
239
|
-
* - `medium`: the writer self-verifies; a separate independent verifier
|
|
240
|
-
* runs only when `writerProfile` is `"small"` -- the small-model bias
|
|
241
|
-
* raises the tier by one for verification purposes (medium -> high). An
|
|
242
|
-
* unknown or omitted writer profile resolves to `"small"` before it
|
|
243
|
-
* reaches this function (see `resolveWriterProfile`), so an unrecognized
|
|
244
|
-
* profile never lowers a tier below what a known small model would get.
|
|
245
|
-
* - `high` or `unassessable` (a failed or unrecognized native assessment is
|
|
246
|
-
* always treated as high): the writer self-verifies and an independent
|
|
247
|
-
* verifier always runs.
|
|
425
|
+
* - `passive`: structural readback by the parent only; no verifier, no tests.
|
|
426
|
+
* - `medium`: the writer self-verifies; a separate independent verifier runs
|
|
427
|
+
* only when `writerProfile` is `"small"` -- the small-model bias raises the
|
|
428
|
+
* tier by one for verification purposes (medium -> high). An unknown or
|
|
429
|
+
* omitted writer profile resolves to `"small"` before it reaches this
|
|
430
|
+
* function (see `resolveWriterProfile`), so an unrecognized profile never
|
|
431
|
+
* lowers a tier below what a known small model would get.
|
|
432
|
+
* - `high` or `unassessable` (a failed or unrecognized native assessment is
|
|
433
|
+
* always treated as high): the writer self-verifies and an independent
|
|
434
|
+
* verifier always runs.
|
|
248
435
|
*/
|
|
249
436
|
export function verificationPlan(input ) {
|
|
250
437
|
const { rddLine, risk, writerProfile } = input;
|
|
251
438
|
|
|
252
439
|
if (rddLine === RDD_LINE.ON) {
|
|
253
440
|
const outcome = input.nativeReviewOutcome ?? NATIVE_REVIEW_OUTCOME.UNKNOWN;
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
writerSelfVerification: false,
|
|
258
|
-
structuralReadbackOnly: true,
|
|
259
|
-
independentVerifier: false,
|
|
260
|
-
reason: "receipt-driven development is on and the native review closed for this candidate; the assessment also reports passive risk: a structural readback by the parent replaces both the writer's self-verification and any separate verifier.",
|
|
261
|
-
});
|
|
262
|
-
}
|
|
263
|
-
return Object.freeze({
|
|
264
|
-
writerSelfVerification: true,
|
|
265
|
-
structuralReadbackOnly: false,
|
|
266
|
-
independentVerifier: false,
|
|
267
|
-
reason: "receipt-driven development is on and the native review closed for this candidate: the writer's self-verification is the record and the closed native review was the independent check the writer cannot influence, so no separate verifier is required.",
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
// The on branch holds only while the native review reaches a terminal
|
|
271
|
-
// outcome for this candidate. Anything else -- declined, unavailable, or
|
|
272
|
-
// unknown -- falls back to the exact same risk-gated path as off.
|
|
441
|
+
const clause = outcome === NATIVE_REVIEW_OUTCOME.CLOSED
|
|
442
|
+
? "the native review closed for this candidate"
|
|
443
|
+
: nonClosedOutcomeClause(outcome);
|
|
273
444
|
return riskGatedPlan(
|
|
274
|
-
`receipt-driven development is on
|
|
445
|
+
`receipt-driven development is on and ${clause}; the native review is an additional outside view that never replaces verification, so the risk-gated path applies exactly as receipt-driven development off, and`,
|
|
275
446
|
risk,
|
|
276
447
|
writerProfile,
|
|
277
448
|
);
|