@gajae-code/coding-agent 0.14.2 → 0.15.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/CHANGELOG.md +120 -1
- package/dist/types/async/job-manager.d.ts +4 -1
- package/dist/types/autoresearch/dashboard.d.ts +29 -4
- package/dist/types/autoresearch/data-context.d.ts +25 -0
- package/dist/types/autoresearch/git.d.ts +65 -7
- package/dist/types/autoresearch/harness.d.ts +58 -0
- package/dist/types/autoresearch/prompts.d.ts +51 -0
- package/dist/types/autoresearch/runs.d.ts +173 -0
- package/dist/types/autoresearch/types.d.ts +9 -139
- package/dist/types/capability/types.d.ts +20 -0
- package/dist/types/cli/accounts-cli.d.ts +1 -0
- package/dist/types/commands/{rlm.d.ts → autoresearch.d.ts} +2 -4
- package/dist/types/config/autorouting-contract.d.ts +146 -0
- package/dist/types/config/autorouting-generator.d.ts +40 -0
- package/dist/types/config/autorouting-tier-map.d.ts +16844 -0
- package/dist/types/config/autorouting.d.ts +35 -0
- package/dist/types/config/model-discovery-manager.d.ts +8 -1
- package/dist/types/config/model-registry.d.ts +30 -1
- package/dist/types/config/provider-selection-policy.d.ts +23 -0
- package/dist/types/config/settings-schema.d.ts +61 -3
- package/dist/types/config/settings.d.ts +3 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/coordinator-mcp/durability.d.ts +29 -0
- package/dist/types/coordinator-mcp/event-webhook.d.ts +50 -0
- package/dist/types/coordinator-mcp/question-state.d.ts +1 -1
- package/dist/types/coordinator-mcp/server.d.ts +14 -0
- package/dist/types/crash/index-store.d.ts +3 -0
- package/dist/types/crash/record-loader.d.ts +2 -0
- package/dist/types/crash/upstream/relay.d.ts +5 -3
- package/dist/types/cursor.d.ts +12 -0
- package/dist/types/defaults/gjc-defaults.d.ts +35 -1
- package/dist/types/defaults/gjc-skills.generated.d.ts +1 -1
- package/dist/types/discovery/helpers.d.ts +1 -1
- package/dist/types/edit/index.d.ts +2 -1
- package/dist/types/eval/py/executor.d.ts +2 -0
- package/dist/types/extensibility/extensions/loader.d.ts +32 -0
- package/dist/types/extensibility/gjc-plugins/types.d.ts +1 -1
- package/dist/types/extensibility/skills.d.ts +2 -0
- package/dist/types/gjc-runtime/autoresearch-runtime.d.ts +194 -0
- package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/psmux-detect.d.ts +1 -1
- package/dist/types/gjc-runtime/python-transcript.d.ts +19 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +2 -8
- package/dist/types/gjc-runtime/session-layout.d.ts +6 -3
- package/dist/types/gjc-runtime/state-renderer.d.ts +0 -22
- package/dist/types/gjc-runtime/state-schema.d.ts +7 -7
- package/dist/types/gjc-runtime/tmux-common.d.ts +2 -2
- package/dist/types/gjc-runtime/ultragoal-change-set.d.ts +38 -1
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +2 -24
- package/dist/types/gjc-runtime/ultragoal-validation-policy.d.ts +73 -0
- package/dist/types/gjc-runtime/workflow-recovery-projection.d.ts +100 -0
- package/dist/types/hooks/skill-keywords.d.ts +1 -1
- package/dist/types/main.d.ts +0 -10
- package/dist/types/modes/acp/acp-agent.d.ts +13 -6
- package/dist/types/modes/components/model-selector.d.ts +14 -0
- package/dist/types/modes/components/skill-hud/render.d.ts +6 -1
- package/dist/types/modes/components/smart-routing-panel.d.ts +82 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +14 -0
- package/dist/types/modes/interactive-mode.d.ts +3 -0
- package/dist/types/modes/types.d.ts +9 -0
- package/dist/types/rlm/artifacts.d.ts +4 -4
- package/dist/types/runtime/optional-runtime-services.d.ts +2 -1
- package/dist/types/runtime/workspace-tree-service.d.ts +5 -1
- package/dist/types/runtime-mcp/config.d.ts +6 -0
- package/dist/types/runtime-mcp/manager.d.ts +10 -0
- package/dist/types/sdk/acp/adapter.d.ts +0 -4
- package/dist/types/sdk/broker/broker.d.ts +1 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +57 -2
- package/dist/types/sdk/broker/session-index.d.ts +15 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +6 -0
- package/dist/types/sdk/bus/chat-daemon-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/index.d.ts +8 -0
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -2
- package/dist/types/sdk/client/client.d.ts +39 -4
- package/dist/types/sdk/host/host.d.ts +1 -0
- package/dist/types/sdk/host/internal-autorouting-state.d.ts +3 -0
- package/dist/types/sdk/host/model-pin.d.ts +29 -0
- package/dist/types/sdk/host/session-runtime.d.ts +2 -1
- package/dist/types/sdk/lifecycle-session.d.ts +13 -0
- package/dist/types/sdk/router/session-router.d.ts +27 -1
- package/dist/types/sdk/session.d.ts +11 -1
- package/dist/types/session/agent-session.d.ts +36 -6
- package/dist/types/session/artifacts.d.ts +16 -1
- package/dist/types/session/internal/managed-session-storage.d.ts +7 -0
- package/dist/types/session/session-manager.d.ts +84 -2
- package/dist/types/session/session-staging-paths.d.ts +3 -0
- package/dist/types/skill-state/canonical-skills.d.ts +1 -1
- package/dist/types/skill-state/workflow-hud.d.ts +12 -21
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +1 -0
- package/dist/types/slash-commands/helpers/autorouting-status.d.ts +8 -0
- package/dist/types/system-prompt.d.ts +23 -0
- package/dist/types/task/executor.d.ts +35 -4
- package/dist/types/task/index.d.ts +17 -3
- package/dist/types/task/receipt.d.ts +3 -1
- package/dist/types/task/types.d.ts +144 -0
- package/dist/types/tools/atomic-file-write.d.ts +72 -0
- package/dist/types/tools/descriptors.d.ts +1 -0
- package/dist/types/tools/index.d.ts +36 -1
- package/dist/types/tools/move-session.d.ts +40 -0
- package/dist/types/tools/python.d.ts +12 -0
- package/dist/types/tools/resource-gc.d.ts +0 -3
- package/dist/types/tools/search.d.ts +8 -1
- package/dist/types/tools/skill.d.ts +9 -4
- package/dist/types/tools/subagent.d.ts +33 -3
- package/dist/types/utils/xml-escape.d.ts +2 -0
- package/dist/types/workflow/workflow-intent-diff.d.ts +2 -2
- package/dist/types/workflow/workflow-intent-report-consumer.d.ts +1 -1
- package/package.json +11 -12
- package/scripts/build-sdk-package-smoke.ts +7 -5
- package/scripts/check-autorouting-tier-map.ts +183 -0
- package/scripts/generate-sdk-operation-inventory.ts +12 -0
- package/scripts/generate-tool-catalog.ts +40 -5
- package/src/async/job-manager.ts +5 -2
- package/src/autoresearch/dashboard.ts +134 -314
- package/src/autoresearch/data-context.ts +35 -0
- package/src/autoresearch/git.ts +186 -26
- package/src/autoresearch/{helpers.ts → harness.ts} +65 -40
- package/src/autoresearch/{prompt-setup.md → prompts/prompt-setup.md} +7 -7
- package/src/autoresearch/prompts/prompt.md +103 -0
- package/src/autoresearch/prompts.ts +126 -0
- package/src/autoresearch/runs.ts +708 -0
- package/src/autoresearch/types.ts +9 -150
- package/src/capability/index.ts +4 -4
- package/src/capability/types.ts +20 -0
- package/src/cli/accounts-cli.ts +21 -5
- package/src/cli/config-cli.ts +25 -1
- package/src/cli/fast-help.ts +1 -2
- package/src/cli/list-models.ts +5 -8
- package/src/cli/setup-cli.ts +8 -0
- package/src/cli.ts +2 -21
- package/src/commands/autoresearch.ts +33 -0
- package/src/commands/coordinator.ts +15 -0
- package/src/commands/launch.ts +2 -4
- package/src/commands/quick-lane.ts +1 -1
- package/src/commands/sdk.ts +24 -0
- package/src/commands/state.ts +1 -1
- package/src/config/autorouting-contract.ts +474 -0
- package/src/config/autorouting-generator.ts +238 -0
- package/src/config/autorouting-tier-map.ts +6108 -0
- package/src/config/autorouting.ts +120 -0
- package/src/config/model-discovery-manager.ts +42 -11
- package/src/config/model-registry.ts +348 -68
- package/src/config/provider-selection-policy.ts +60 -9
- package/src/config/settings-schema.ts +195 -6
- package/src/config/settings.ts +62 -1
- package/src/config.ts +2 -3
- package/src/coordinator/contract.ts +0 -1
- package/src/coordinator-mcp/codex-handoff.ts +68 -42
- package/src/coordinator-mcp/durability.ts +200 -0
- package/src/coordinator-mcp/event-webhook.ts +278 -0
- package/src/coordinator-mcp/question-state.ts +109 -46
- package/src/coordinator-mcp/server.ts +932 -504
- package/src/crash/index-store.ts +126 -22
- package/src/crash/record-loader.ts +7 -0
- package/src/crash/upstream/relay.ts +82 -34
- package/src/cursor.ts +84 -1
- package/src/debug/index.ts +26 -0
- package/src/defaults/gjc/skills/autoresearch/SKILL.md +116 -0
- package/src/defaults/gjc/skills/autoresearch/auto-critic.md +46 -0
- package/src/defaults/gjc/skills/autoresearch/auto-iterate.md +42 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +17 -37
- package/src/defaults/gjc/skills/ralplan/SKILL.md +21 -18
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +6 -17
- package/src/defaults/gjc/skills/ultragoal/ai-slop-cleaner.md +2 -2
- package/src/defaults/gjc-defaults.ts +89 -2
- package/src/defaults/gjc-skills.generated.ts +24 -17
- package/src/discovery/builtin.ts +18 -5
- package/src/discovery/helpers.ts +6 -6
- package/src/edit/index.ts +5 -2
- package/src/eval/py/executor.ts +8 -0
- package/src/extensibility/extensions/loader.ts +135 -13
- package/src/extensibility/extensions/wrapper.ts +1 -2
- package/src/extensibility/gjc-plugins/schema.ts +1 -1
- package/src/extensibility/runtime-skill-discovery.ts +2 -2
- package/src/extensibility/skill-management.ts +2 -3
- package/src/extensibility/skills.ts +16 -8
- package/src/gjc-runtime/autoresearch-runtime.ts +1509 -0
- package/src/gjc-runtime/gc-render.ts +0 -1
- package/src/gjc-runtime/gc-runtime.ts +1 -11
- package/src/gjc-runtime/launch-tmux.ts +3 -3
- package/src/gjc-runtime/psmux-detect.ts +2 -2
- package/src/gjc-runtime/python-transcript.ts +58 -0
- package/src/gjc-runtime/ralplan-runtime.ts +6 -18
- package/src/gjc-runtime/session-layout.ts +18 -7
- package/src/gjc-runtime/session-state-sidecar.ts +58 -9
- package/src/gjc-runtime/state-renderer.ts +0 -38
- package/src/gjc-runtime/state-runtime.ts +43 -22
- package/src/gjc-runtime/state-schema.ts +1 -1
- package/src/gjc-runtime/tmux-common.ts +7 -7
- package/src/gjc-runtime/ultragoal-change-set.ts +232 -11
- package/src/gjc-runtime/ultragoal-runtime.ts +309 -114
- package/src/gjc-runtime/ultragoal-validation-policy.ts +247 -0
- package/src/gjc-runtime/workflow-command-ref.ts +15 -11
- package/src/gjc-runtime/workflow-manifest.generated.json +413 -532
- package/src/gjc-runtime/workflow-manifest.ts +43 -83
- package/src/gjc-runtime/workflow-recovery-projection.ts +616 -0
- package/src/hooks/skill-keywords.ts +3 -3
- package/src/hooks/skill-state.ts +2 -2
- package/src/internal-urls/docs-index.generated.ts +26 -24
- package/src/lsp/index.ts +25 -5
- package/src/main.ts +2 -27
- package/src/modes/acp/acp-agent.ts +200 -75
- package/src/modes/components/model-selector.ts +216 -13
- package/src/modes/components/oauth-selector.ts +5 -5
- package/src/modes/components/skill-hud/render.ts +173 -35
- package/src/modes/components/smart-routing-panel.ts +531 -0
- package/src/modes/components/tool-status-header.ts +6 -3
- package/src/modes/controllers/command-controller.ts +17 -7
- package/src/modes/controllers/input-controller.ts +44 -9
- package/src/modes/controllers/runtime-mcp-command-controller.ts +4 -0
- package/src/modes/controllers/selector-controller.ts +298 -65
- package/src/modes/interactive-mode.ts +8 -1
- package/src/modes/shared/agent-wire/workflow-gate-types.ts +1 -1
- package/src/modes/types.ts +9 -1
- package/src/prompts/agents/planner.md +1 -1
- package/src/prompts/system/system-prompt.md +1 -1
- package/src/prompts/system/volatile-project-context.md +2 -1
- package/src/prompts/tools/move-session.md +15 -0
- package/src/prompts/tools/python.md +12 -0
- package/src/prompts/tools/skill-discovery.md +1 -1
- package/src/prompts/tools/skill.md +2 -2
- package/src/prompts/tools/task-summary.md +1 -0
- package/src/prompts/tools/task.md +6 -0
- package/src/rlm/artifacts.ts +12 -10
- package/src/runtime/optional-runtime-services.ts +3 -2
- package/src/runtime/workspace-tree-service.ts +11 -3
- package/src/runtime-mcp/config.ts +8 -1
- package/src/runtime-mcp/manager.ts +33 -0
- package/src/sdk/acp/adapter.ts +48 -1
- package/src/sdk/broker/broker.ts +30 -2
- package/src/sdk/broker/discovery.ts +217 -2
- package/src/sdk/broker/lifecycle.ts +385 -59
- package/src/sdk/broker/session-index.ts +243 -48
- package/src/sdk/broker/transport.ts +1 -0
- package/src/sdk/bus/chat-daemon-control.ts +8 -2
- package/src/sdk/bus/chat-daemon-runtime.ts +5 -0
- package/src/sdk/bus/index.ts +208 -11
- package/src/sdk/bus/kind-aware-reconciliation.ts +16 -0
- package/src/sdk/bus/reconciliation-store.ts +27 -5
- package/src/sdk/bus/telegram-daemon-contract.ts +12 -2
- package/src/sdk/client/client.ts +204 -22
- package/src/sdk/host/host.ts +16 -0
- package/src/sdk/host/internal-autorouting-state.ts +13 -0
- package/src/sdk/host/model-pin.ts +101 -0
- package/src/sdk/host/reverse-leases.ts +2 -1
- package/src/sdk/host/session-runtime.test.ts +224 -1
- package/src/sdk/host/session-runtime.ts +125 -37
- package/src/sdk/lifecycle/service.ts +3 -1
- package/src/sdk/lifecycle-session.ts +42 -1
- package/src/sdk/protocol/operation-inventory.generated.json +66 -0
- package/src/sdk/router/session-router.ts +375 -36
- package/src/sdk/session.ts +547 -47
- package/src/session/account-inventory.ts +1 -1
- package/src/session/agent-session.ts +765 -189
- package/src/session/artifacts.ts +234 -4
- package/src/session/internal/managed-session-storage.ts +91 -4
- package/src/session/provider-safety-stop-hint.ts +3 -2
- package/src/session/session-manager.ts +775 -16
- package/src/session/session-staging-paths.ts +8 -0
- package/src/setup/hermes/templates/operator-instructions.v1.md +0 -1
- package/src/setup/host-plugin-setup.ts +2 -2
- package/src/skill-state/active-state.ts +2 -2
- package/src/skill-state/canonical-skills.ts +1 -1
- package/src/skill-state/initial-phase.ts +1 -1
- package/src/skill-state/workflow-hud.ts +41 -41
- package/src/skill-state/workflow-mutation-guard.ts +26 -7
- package/src/slash-commands/builtin-registry.ts +77 -0
- package/src/slash-commands/helpers/autorouting-status.ts +55 -0
- package/src/system-prompt.ts +102 -5
- package/src/task/discovery.ts +2 -3
- package/src/task/executor.ts +617 -43
- package/src/task/index.ts +262 -15
- package/src/task/receipt.ts +30 -0
- package/src/task/render.ts +11 -1
- package/src/task/types.ts +316 -0
- package/src/tools/atomic-file-write.ts +594 -0
- package/src/tools/bisect.ts +3 -2
- package/src/tools/descriptors.test.ts +3 -0
- package/src/tools/descriptors.ts +24 -0
- package/src/tools/image-gen.ts +5 -1
- package/src/tools/index.ts +62 -5
- package/src/tools/move-session.ts +107 -0
- package/src/tools/python.ts +205 -0
- package/src/tools/read.ts +88 -15
- package/src/tools/renderers.ts +2 -0
- package/src/tools/resource-gc.ts +8 -177
- package/src/tools/search.ts +30 -6
- package/src/tools/skill-discovery.ts +1 -0
- package/src/tools/skill.ts +37 -7
- package/src/tools/subagent-render.ts +119 -13
- package/src/tools/subagent.ts +91 -74
- package/src/tools/tool-catalog.generated.ts +64 -2
- package/src/tools/write.ts +16 -12
- package/src/utils/xml-escape.ts +14 -0
- package/src/web/search/providers/codex.ts +2 -2
- package/src/workflow/workflow-intent-diff.ts +13 -12
- package/src/workflow/workflow-intent-report-consumer.ts +6 -6
- package/dist/types/autoresearch/helpers.d.ts +0 -24
- package/dist/types/autoresearch/index.d.ts +0 -2
- package/dist/types/autoresearch/state.d.ts +0 -17
- package/dist/types/autoresearch/storage.d.ts +0 -142
- package/dist/types/autoresearch/tools/init-experiment.d.ts +0 -31
- package/dist/types/autoresearch/tools/log-experiment.d.ts +0 -23
- package/dist/types/autoresearch/tools/run-experiment.d.ts +0 -8
- package/dist/types/autoresearch/tools/update-notes.d.ts +0 -12
- package/dist/types/commands/team.d.ts +0 -24
- package/dist/types/gjc-runtime/team-gc.d.ts +0 -7
- package/dist/types/gjc-runtime/team-launch.d.ts +0 -61
- package/dist/types/gjc-runtime/team-notify.d.ts +0 -45
- package/dist/types/gjc-runtime/team-runtime.d.ts +0 -336
- package/dist/types/gjc-runtime/team-store.d.ts +0 -168
- package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +0 -43
- package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +0 -92
- package/dist/types/gjc-runtime/team-workers.d.ts +0 -83
- package/dist/types/rlm/index.d.ts +0 -47
- package/dist/types/rlm/preset.d.ts +0 -23
- package/dist/types/rlm/python-tool.d.ts +0 -16
- package/src/autoresearch/command-resume.md +0 -14
- package/src/autoresearch/index.ts +0 -536
- package/src/autoresearch/prompt.md +0 -103
- package/src/autoresearch/resume-message.md +0 -10
- package/src/autoresearch/state.ts +0 -273
- package/src/autoresearch/storage.ts +0 -699
- package/src/autoresearch/tools/init-experiment.ts +0 -272
- package/src/autoresearch/tools/log-experiment.ts +0 -524
- package/src/autoresearch/tools/run-experiment.ts +0 -475
- package/src/autoresearch/tools/update-notes.ts +0 -109
- package/src/commands/rlm.ts +0 -19
- package/src/commands/team.ts +0 -238
- package/src/defaults/gjc/skills/deep-interview/auto-research-greenfield.md +0 -42
- package/src/defaults/gjc/skills/team/SKILL.md +0 -467
- package/src/gjc-runtime/team-gc.ts +0 -49
- package/src/gjc-runtime/team-launch.ts +0 -404
- package/src/gjc-runtime/team-notify.ts +0 -326
- package/src/gjc-runtime/team-runtime.ts +0 -5923
- package/src/gjc-runtime/team-store.ts +0 -878
- package/src/gjc-runtime/team-worker-heartbeat.ts +0 -149
- package/src/gjc-runtime/team-worker-memory-guard.ts +0 -363
- package/src/gjc-runtime/team-workers.ts +0 -1123
- package/src/prompts/system/rlm-report-command.md +0 -1
- package/src/prompts/system/rlm-research.md +0 -23
- package/src/rlm/index.ts +0 -365
- package/src/rlm/preset.ts +0 -76
- package/src/rlm/python-tool.ts +0 -68
|
@@ -62,8 +62,51 @@ import {
|
|
|
62
62
|
writeArtifact,
|
|
63
63
|
writeGuardedJsonAtomic,
|
|
64
64
|
} from "./state-writer";
|
|
65
|
+
import {
|
|
66
|
+
categorizeComputerChangePath,
|
|
67
|
+
ciDevChangedPathRows,
|
|
68
|
+
computeCheckpointChangeSet,
|
|
69
|
+
computeUltragoalReviewSourceHash,
|
|
70
|
+
mergeChangeSetPaths,
|
|
71
|
+
normalizeChangeSetPath,
|
|
72
|
+
parseGitNameStatus,
|
|
73
|
+
parseGitUntrackedPaths,
|
|
74
|
+
parseUnifiedDiffPaths,
|
|
75
|
+
resolveGitBase,
|
|
76
|
+
spawnText,
|
|
77
|
+
type UltragoalChangeCategory,
|
|
78
|
+
type UltragoalChangeSet,
|
|
79
|
+
type UltragoalChangeSetPath,
|
|
80
|
+
type UltragoalChangeStatus,
|
|
81
|
+
} from "./ultragoal-change-set";
|
|
82
|
+
import {
|
|
83
|
+
resolveUltragoalValidationApplicability,
|
|
84
|
+
type UltragoalValidationApplicability,
|
|
85
|
+
type UltragoalValidationLane,
|
|
86
|
+
type UltragoalValidationLaneSelection,
|
|
87
|
+
validationLaneSelectionFor,
|
|
88
|
+
} from "./ultragoal-validation-policy";
|
|
65
89
|
import { resolveWorkflowSetting } from "./workflow-settings";
|
|
66
90
|
|
|
91
|
+
export {
|
|
92
|
+
categorizeComputerChangePath,
|
|
93
|
+
ciDevChangedPathRows,
|
|
94
|
+
computeCheckpointChangeSet,
|
|
95
|
+
computeUltragoalReviewSourceHash,
|
|
96
|
+
mergeChangeSetPaths,
|
|
97
|
+
normalizeChangeSetPath,
|
|
98
|
+
normalizeRepoPath,
|
|
99
|
+
parseGitNameStatus,
|
|
100
|
+
parseGitUntrackedPaths,
|
|
101
|
+
parseUnifiedDiffPaths,
|
|
102
|
+
resolveGitBase,
|
|
103
|
+
spawnText,
|
|
104
|
+
type UltragoalChangeCategory,
|
|
105
|
+
type UltragoalChangeSet,
|
|
106
|
+
type UltragoalChangeSetPath,
|
|
107
|
+
type UltragoalChangeStatus,
|
|
108
|
+
} from "./ultragoal-change-set";
|
|
109
|
+
|
|
67
110
|
export {
|
|
68
111
|
captureUltragoalRecoverySnapshot,
|
|
69
112
|
parseStrictTerminalTranscript,
|
|
@@ -1526,33 +1569,6 @@ function formatExpectedKindWords(words: string[]): string {
|
|
|
1526
1569
|
|
|
1527
1570
|
export type SurfaceFamily = "web" | "cli" | "native" | "api-package" | "algorithm-math" | "unknown";
|
|
1528
1571
|
|
|
1529
|
-
export type UltragoalChangeStatus = "added" | "modified" | "deleted" | "renamed" | "copied" | "unknown";
|
|
1530
|
-
export type UltragoalChangeCategory =
|
|
1531
|
-
| "code"
|
|
1532
|
-
| "generated-binding"
|
|
1533
|
-
| "tool"
|
|
1534
|
-
| "settings-registry"
|
|
1535
|
-
| "prompt-doc-behavior"
|
|
1536
|
-
| "docs-static"
|
|
1537
|
-
| "other";
|
|
1538
|
-
export interface UltragoalChangeSetPath extends JsonObject {
|
|
1539
|
-
path: string;
|
|
1540
|
-
status: UltragoalChangeStatus;
|
|
1541
|
-
oldPath?: string;
|
|
1542
|
-
category?: UltragoalChangeCategory;
|
|
1543
|
-
}
|
|
1544
|
-
export interface UltragoalChangeSet extends JsonObject {
|
|
1545
|
-
source: "checkpoint-git" | "review-pr" | "review-branch" | "review-worktree" | "review-spec";
|
|
1546
|
-
baseRef?: string;
|
|
1547
|
-
headRef?: string;
|
|
1548
|
-
mergeBase?: string;
|
|
1549
|
-
paths: UltragoalChangeSetPath[];
|
|
1550
|
-
rawDiffStat?: string;
|
|
1551
|
-
rawDiff?: string;
|
|
1552
|
-
captureIncomplete?: boolean;
|
|
1553
|
-
trusted: true;
|
|
1554
|
-
}
|
|
1555
|
-
|
|
1556
1572
|
const MANDATORY_COMPUTER_CASE_IDS = [
|
|
1557
1573
|
"kill-switch-bypass",
|
|
1558
1574
|
"suspended-enforcement",
|
|
@@ -1562,40 +1578,6 @@ const MANDATORY_COMPUTER_CASE_IDS = [
|
|
|
1562
1578
|
"runaway-loop-halt",
|
|
1563
1579
|
"blast-radius",
|
|
1564
1580
|
] as const;
|
|
1565
|
-
const TOOLS_INDEX_PATH = "packages/coding-agent/src/tools/index.ts";
|
|
1566
|
-
|
|
1567
|
-
export function normalizeRepoPath(value: string): string {
|
|
1568
|
-
return value.replaceAll("\\\\", "/").replace(/^\.\//, "");
|
|
1569
|
-
}
|
|
1570
|
-
|
|
1571
|
-
export function normalizeChangeSetPath(value: string): string {
|
|
1572
|
-
return value.replace(/^\.\//, "");
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
export function categorizeComputerChangePath(value: string): UltragoalChangeCategory {
|
|
1576
|
-
const normalized = normalizeRepoPath(value);
|
|
1577
|
-
if (normalized.startsWith("crates/pi-natives/src/computer/")) return "code";
|
|
1578
|
-
if (/^packages\/natives\/native\/index\.(?:d\.ts|js)$/.test(normalized)) return "generated-binding";
|
|
1579
|
-
if (
|
|
1580
|
-
normalized === "packages/coding-agent/src/tools/computer.ts" ||
|
|
1581
|
-
normalized.startsWith("packages/coding-agent/src/tools/computer/")
|
|
1582
|
-
)
|
|
1583
|
-
return "tool";
|
|
1584
|
-
if (
|
|
1585
|
-
normalized === TOOLS_INDEX_PATH ||
|
|
1586
|
-
normalized === "packages/coding-agent/src/tools/renderers.ts" ||
|
|
1587
|
-
normalized === "packages/coding-agent/src/config/settings-schema.ts"
|
|
1588
|
-
)
|
|
1589
|
-
return "settings-registry";
|
|
1590
|
-
if (
|
|
1591
|
-
normalized === "packages/coding-agent/src/prompts/tools/computer.md" ||
|
|
1592
|
-
normalized === "packages/coding-agent/src/defaults/gjc/skills/ultragoal/SKILL.md" ||
|
|
1593
|
-
normalized === "packages/coding-agent/src/prompts/agents/executor.md"
|
|
1594
|
-
)
|
|
1595
|
-
return "prompt-doc-behavior";
|
|
1596
|
-
if (normalized === "docs/tools/computer.md" || normalized === "docs/computer-use/README.md") return "docs-static";
|
|
1597
|
-
return "other";
|
|
1598
|
-
}
|
|
1599
1581
|
|
|
1600
1582
|
function isComputerControlSurfaceCategory(category: UltragoalChangeCategory): boolean {
|
|
1601
1583
|
// Shared behavior registries are intentionally conservative: a path-only or
|
|
@@ -2500,6 +2482,98 @@ function validateDeferredCompletionQualityGate(
|
|
|
2500
2482
|
"deferredToBatch.changeSet.changeSetHash does not match declared paths; omit changeSetHash and the runtime computes it",
|
|
2501
2483
|
);
|
|
2502
2484
|
}
|
|
2485
|
+
/** #4560: declared lane-selection proof shape on the quality gate. */
|
|
2486
|
+
type DeclaredValidationLaneSelection = UltragoalValidationLaneSelection;
|
|
2487
|
+
|
|
2488
|
+
function readDeclaredValidationLaneSelection(gate: JsonObject): DeclaredValidationLaneSelection | undefined {
|
|
2489
|
+
const declared = qualityGateObject(gate.validationLaneSelection);
|
|
2490
|
+
if (!declared) return undefined;
|
|
2491
|
+
const riskClass = nonEmptyString(declared.riskClass);
|
|
2492
|
+
const reasons = stringArray(declared.reasons);
|
|
2493
|
+
const omittedLanes = stringArray(declared.omittedLanes);
|
|
2494
|
+
if (!riskClass || !reasons || !omittedLanes) {
|
|
2495
|
+
throw new Error(
|
|
2496
|
+
"validationLaneSelection must carry riskClass, reasons, and omittedLanes string arrays mirroring the runtime selection",
|
|
2497
|
+
);
|
|
2498
|
+
}
|
|
2499
|
+
if (riskClass !== "low" && riskClass !== "high")
|
|
2500
|
+
throw new Error('validationLaneSelection.riskClass must be "low" or "high"');
|
|
2501
|
+
if (omittedLanes.some(lane => !["cleaner", "architect", "qa", "terminal-critic"].includes(lane)))
|
|
2502
|
+
throw new Error("validationLaneSelection.omittedLanes contains an unsupported lane");
|
|
2503
|
+
return { riskClass, reasons, omittedLanes: omittedLanes as UltragoalValidationLane[] };
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
/**
|
|
2507
|
+
* #4560: validate a declared low-risk lane reduction against the
|
|
2508
|
+
* runtime-computed applicability. The runtime selection is authoritative: a
|
|
2509
|
+
* declaration that disagrees with the computed risk class, reasons, or
|
|
2510
|
+
* omitted-lane set fails closed and the full cohort stays mandatory.
|
|
2511
|
+
*/
|
|
2512
|
+
function validateDeclaredValidationLaneSelection(
|
|
2513
|
+
declared: DeclaredValidationLaneSelection,
|
|
2514
|
+
applicability: UltragoalValidationApplicability,
|
|
2515
|
+
found: QualityGateDiagnostics,
|
|
2516
|
+
): boolean {
|
|
2517
|
+
if (declared.riskClass !== applicability.riskClass) {
|
|
2518
|
+
found.add(
|
|
2519
|
+
"validationLaneSelection",
|
|
2520
|
+
"selection_mismatch",
|
|
2521
|
+
"declared validationLaneSelection riskClass does not match the runtime-computed risk class",
|
|
2522
|
+
);
|
|
2523
|
+
return false;
|
|
2524
|
+
}
|
|
2525
|
+
const expected = validationLaneSelectionFor(applicability);
|
|
2526
|
+
if (
|
|
2527
|
+
declared.reasons.length !== expected.reasons.length ||
|
|
2528
|
+
declared.reasons.some((reason, index) => reason !== expected.reasons[index])
|
|
2529
|
+
) {
|
|
2530
|
+
found.add(
|
|
2531
|
+
"validationLaneSelection.reasons",
|
|
2532
|
+
"reasons_mismatch",
|
|
2533
|
+
"declared validationLaneSelection reasons must exactly mirror the runtime-computed selection basis",
|
|
2534
|
+
);
|
|
2535
|
+
return false;
|
|
2536
|
+
}
|
|
2537
|
+
const expectedOmitted = expected.omittedLanes;
|
|
2538
|
+
const declaredOmitted = new Set(declared.omittedLanes);
|
|
2539
|
+
if (declaredOmitted.has("qa")) {
|
|
2540
|
+
found.add(
|
|
2541
|
+
"validationLaneSelection",
|
|
2542
|
+
"qa_lane_mandatory",
|
|
2543
|
+
"validationLaneSelection can never omit the qa lane; verification is mandatory at every boundary",
|
|
2544
|
+
);
|
|
2545
|
+
return false;
|
|
2546
|
+
}
|
|
2547
|
+
if (declaredOmitted.size !== expectedOmitted.length || expectedOmitted.some(lane => !declaredOmitted.has(lane))) {
|
|
2548
|
+
found.add(
|
|
2549
|
+
"validationLaneSelection",
|
|
2550
|
+
"omitted_lanes_mismatch",
|
|
2551
|
+
"declared validationLaneSelection omittedLanes must exactly mirror the runtime-computed inapplicable lanes",
|
|
2552
|
+
);
|
|
2553
|
+
return false;
|
|
2554
|
+
}
|
|
2555
|
+
return applicability.riskClass === "low";
|
|
2556
|
+
}
|
|
2557
|
+
|
|
2558
|
+
/** #4560: newest joined cohort (generation + frozen sourceHash) in the ledger. */
|
|
2559
|
+
function latestJoinedCohortSourceHash(
|
|
2560
|
+
ledger: readonly UltragoalLedgerEvent[],
|
|
2561
|
+
): { reviewGeneration: number; sourceHash: string } | undefined {
|
|
2562
|
+
let latest: { reviewGeneration: number; sourceHash: string } | undefined;
|
|
2563
|
+
for (const event of ledger) {
|
|
2564
|
+
if (event.event !== "goal_checkpointed" || event.status !== "complete") continue;
|
|
2565
|
+
const cohort = qualityGateObject(
|
|
2566
|
+
qualityGateObject(event.qualityGateJson)?.iteration as JsonObject | undefined,
|
|
2567
|
+
)?.reviewCohort;
|
|
2568
|
+
const record = qualityGateObject(cohort);
|
|
2569
|
+
if (!record) continue;
|
|
2570
|
+
const reviewGeneration = record.reviewGeneration;
|
|
2571
|
+
const sourceHash = nonEmptyString(record.sourceHash);
|
|
2572
|
+
if (typeof reviewGeneration !== "number" || !sourceHash) continue;
|
|
2573
|
+
if (!latest || reviewGeneration >= latest.reviewGeneration) latest = { reviewGeneration, sourceHash };
|
|
2574
|
+
}
|
|
2575
|
+
return latest;
|
|
2576
|
+
}
|
|
2503
2577
|
const COHORT_LANE_KEYS = ["cleaner", "architect", "qa"] as const;
|
|
2504
2578
|
|
|
2505
2579
|
/**
|
|
@@ -2509,7 +2583,11 @@ const COHORT_LANE_KEYS = ["cleaner", "architect", "qa"] as const;
|
|
|
2509
2583
|
* generations are delta-only. Cohort state rides the existing `iteration` gate key so
|
|
2510
2584
|
* no new top-level quality-gate key is introduced.
|
|
2511
2585
|
*/
|
|
2512
|
-
function validateReviewCohort(
|
|
2586
|
+
function validateReviewCohort(
|
|
2587
|
+
gate: JsonObject,
|
|
2588
|
+
iteration: JsonObject,
|
|
2589
|
+
options: { lowRiskReduced?: boolean } = {},
|
|
2590
|
+
): void {
|
|
2513
2591
|
const cohort = qualityGateObject(iteration.reviewCohort);
|
|
2514
2592
|
if (!cohort) throw new Error("qualityGate iteration.reviewCohort is required at the review boundary");
|
|
2515
2593
|
const generation = cohort.reviewGeneration;
|
|
@@ -2524,7 +2602,15 @@ function validateReviewCohort(gate: JsonObject, iteration: JsonObject): void {
|
|
|
2524
2602
|
const unsupportedLanes = Object.keys(lanes).filter(key => !(COHORT_LANE_KEYS as readonly string[]).includes(key));
|
|
2525
2603
|
if (unsupportedLanes.length > 0)
|
|
2526
2604
|
throw new Error(`iteration.reviewCohort.lanes contains unsupported lanes: ${unsupportedLanes.join(", ")}`);
|
|
2527
|
-
|
|
2605
|
+
// #4560: on a runtime-selected low-risk single-goal boundary, cleaner and
|
|
2606
|
+
// architect may be omitted only through the deterministic
|
|
2607
|
+
// validationLaneSelection proof validated by the caller; the QA lane and
|
|
2608
|
+
// the frozen source hash stay mandatory, and cohort parallelism is
|
|
2609
|
+
// untouched whenever lanes do run.
|
|
2610
|
+
const requiredLanes: readonly (typeof COHORT_LANE_KEYS)[number][] = options.lowRiskReduced
|
|
2611
|
+
? COHORT_LANE_KEYS.filter(lane => lane === "qa")
|
|
2612
|
+
: [...COHORT_LANE_KEYS];
|
|
2613
|
+
for (const lane of requiredLanes) {
|
|
2528
2614
|
if (Array.isArray(lanes[lane]))
|
|
2529
2615
|
throw new Error(`iteration.reviewCohort.lanes.${lane} must be one lane per generation, not a list`);
|
|
2530
2616
|
const record = qualityGateObject(lanes[lane]);
|
|
@@ -2618,6 +2704,7 @@ async function validateCompletionQualityGate(
|
|
|
2618
2704
|
"executorQa",
|
|
2619
2705
|
"iteration",
|
|
2620
2706
|
"validationBatchClose",
|
|
2707
|
+
"validationLaneSelection",
|
|
2621
2708
|
"criticReview",
|
|
2622
2709
|
]);
|
|
2623
2710
|
const unsupportedKeys = Object.keys(gate).filter(key => !allowedKeys.has(key));
|
|
@@ -2643,8 +2730,15 @@ async function validateCompletionQualityGate(
|
|
|
2643
2730
|
}
|
|
2644
2731
|
const allowedKeys = new Set(
|
|
2645
2732
|
batchMode
|
|
2646
|
-
? [
|
|
2647
|
-
|
|
2733
|
+
? [
|
|
2734
|
+
"architectReview",
|
|
2735
|
+
"executorQa",
|
|
2736
|
+
"iteration",
|
|
2737
|
+
"validationBatchClose",
|
|
2738
|
+
"criticReview",
|
|
2739
|
+
"validationLaneSelection",
|
|
2740
|
+
]
|
|
2741
|
+
: ["architectReview", "executorQa", "iteration", "criticReview", "validationLaneSelection"],
|
|
2648
2742
|
);
|
|
2649
2743
|
const unsupportedKeys = Object.keys(gate).filter(key => !allowedKeys.has(key));
|
|
2650
2744
|
if (unsupportedKeys.length > 0) {
|
|
@@ -2654,14 +2748,52 @@ async function validateCompletionQualityGate(
|
|
|
2654
2748
|
`qualityGate contains unsupported keys: ${unsupportedKeys.join(", ")}`,
|
|
2655
2749
|
);
|
|
2656
2750
|
}
|
|
2751
|
+
// #4560: deterministic risk/applicability selection for expensive boundary
|
|
2752
|
+
// lanes. The runtime — never free-form model prose — decides whether a
|
|
2753
|
+
// low-risk single-goal boundary may omit redundant review ceremony
|
|
2754
|
+
// (cleaner/architect/terminal-critic). QA/targeted verification and the
|
|
2755
|
+
// hash/receipt/join guarantees always remain mandatory. Anything risky or
|
|
2756
|
+
// unprovable keeps today's full heavyweight cohort unchanged. The current
|
|
2757
|
+
// frozen source under review is the gate's own cohort sourceHash.
|
|
2758
|
+
const gateIteration = qualityGateObject(gate.iteration);
|
|
2759
|
+
const gateCohortSourceHash = nonEmptyString(qualityGateObject(gateIteration?.reviewCohort)?.sourceHash);
|
|
2760
|
+
const authoritativeSourceHash = computeUltragoalReviewSourceHash(options.changeSet);
|
|
2761
|
+
if (gateCohortSourceHash && authoritativeSourceHash && gateCohortSourceHash !== authoritativeSourceHash) {
|
|
2762
|
+
found.add(
|
|
2763
|
+
"iteration.reviewCohort.sourceHash",
|
|
2764
|
+
"source_hash_mismatch",
|
|
2765
|
+
"iteration.reviewCohort.sourceHash must equal the runtime-computed digest of the authoritative current source basis",
|
|
2766
|
+
);
|
|
2767
|
+
}
|
|
2768
|
+
const applicability = resolveUltragoalValidationApplicability({
|
|
2769
|
+
changeSet: options.changeSet,
|
|
2770
|
+
requiredGoals: options.plan?.goals.filter(goal => goal.status !== "superseded").length,
|
|
2771
|
+
hasOpenReviewBlockers: options.plan?.goals.some(goal => goal.status === "review_blocked") ?? false,
|
|
2772
|
+
latestCohortSourceHash: options.ledger ? latestJoinedCohortSourceHash(options.ledger)?.sourceHash : undefined,
|
|
2773
|
+
currentSourceHash: gateCohortSourceHash ?? undefined,
|
|
2774
|
+
authoritativeSourceHash,
|
|
2775
|
+
});
|
|
2776
|
+
let laneSelection: DeclaredValidationLaneSelection | undefined;
|
|
2777
|
+
found.check("validationLaneSelection", "selection_invalid", () => {
|
|
2778
|
+
laneSelection = readDeclaredValidationLaneSelection(gate);
|
|
2779
|
+
});
|
|
2780
|
+
const lowRiskReduced =
|
|
2781
|
+
laneSelection !== undefined && validateDeclaredValidationLaneSelection(laneSelection, applicability, found);
|
|
2657
2782
|
const architectReview = qualityGateObject(gate.architectReview);
|
|
2658
2783
|
const executorQa = qualityGateObject(gate.executorQa);
|
|
2659
2784
|
const iteration = qualityGateObject(gate.iteration);
|
|
2660
|
-
|
|
2785
|
+
// #4560: when the runtime-verified selection omits the architect lane, the
|
|
2786
|
+
// boundary must not still demand architect evidence \u2014 otherwise the advertised
|
|
2787
|
+
// omission is unusable and the caller has to run or fabricate the lane anyway.
|
|
2788
|
+
// QA and iteration evidence stay mandatory in every case.
|
|
2789
|
+
const architectRequired = !lowRiskReduced || applicability.lanes.architect.applicable;
|
|
2790
|
+
if ((architectRequired && !architectReview) || !executorQa || !iteration) {
|
|
2661
2791
|
found.add(
|
|
2662
2792
|
"qualityGate",
|
|
2663
2793
|
"missing_required_sections",
|
|
2664
|
-
|
|
2794
|
+
architectRequired
|
|
2795
|
+
? "qualityGate requires architectReview, executorQa, and iteration objects"
|
|
2796
|
+
: "qualityGate requires executorQa and iteration objects",
|
|
2665
2797
|
);
|
|
2666
2798
|
found.throwIfAny();
|
|
2667
2799
|
return;
|
|
@@ -2678,8 +2810,16 @@ async function validateCompletionQualityGate(
|
|
|
2678
2810
|
"checkpoint --status complete blocked: terminal-critic ceiling reached; requires human/leader gjc ultragoal record-critic-gate-override before completion",
|
|
2679
2811
|
);
|
|
2680
2812
|
}
|
|
2813
|
+
// #4560: terminal-critic proportionality. The critic verdict is
|
|
2814
|
+
// mandatory on multi-goal/boundary, high-risk, or evidence-uncertain
|
|
2815
|
+
// runs. A single-goal low-risk run whose joined cohort is clean and
|
|
2816
|
+
// whose immutable source basis is unchanged may satisfy the terminus
|
|
2817
|
+
// through the runtime-verified validationLaneSelection proof instead
|
|
2818
|
+
// of duplicating the already-joined review with another read pass.
|
|
2681
2819
|
const criticReview = qualityGateObject(gate.criticReview);
|
|
2682
|
-
|
|
2820
|
+
const criticProportionallySatisfied =
|
|
2821
|
+
lowRiskReduced && applicability.basisUnchanged && !applicability.hasOpenReviewBlockers;
|
|
2822
|
+
if (criticReview?.verdict !== "OKAY" && !criticProportionallySatisfied) {
|
|
2683
2823
|
found.add(
|
|
2684
2824
|
"criticReview.verdict",
|
|
2685
2825
|
"critic_verdict_not_okay",
|
|
@@ -2695,31 +2835,33 @@ async function validateCompletionQualityGate(
|
|
|
2695
2835
|
);
|
|
2696
2836
|
}
|
|
2697
2837
|
}
|
|
2698
|
-
if (
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2838
|
+
if (architectReview) {
|
|
2839
|
+
if (
|
|
2840
|
+
architectReview.architectureStatus !== CLEAN_ARCHITECT_STATUS ||
|
|
2841
|
+
architectReview.productStatus !== CLEAN_ARCHITECT_STATUS ||
|
|
2842
|
+
architectReview.codeStatus !== CLEAN_ARCHITECT_STATUS ||
|
|
2843
|
+
architectReview.recommendation !== APPROVE_RECOMMENDATION
|
|
2844
|
+
) {
|
|
2845
|
+
found.add(
|
|
2846
|
+
"architectReview",
|
|
2847
|
+
"architect_not_clear",
|
|
2848
|
+
"checkpoint --status complete requires architect review approval: architectReview architecture/product/code must be CLEAR and recommendation must be APPROVE",
|
|
2849
|
+
);
|
|
2850
|
+
}
|
|
2851
|
+
if (!nonEmptyStringArray(architectReview.commands)) {
|
|
2852
|
+
found.add(
|
|
2853
|
+
"architectReview.commands",
|
|
2854
|
+
"missing_command_array",
|
|
2855
|
+
"qualityGate architectReview.commands must be a non-empty string array",
|
|
2856
|
+
);
|
|
2857
|
+
}
|
|
2858
|
+
found.check("architectReview.evidence", "missing_evidence", () =>
|
|
2859
|
+
requireNonEmptyString(architectReview.evidence, "architectReview.evidence"),
|
|
2708
2860
|
);
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
found.add(
|
|
2712
|
-
"architectReview.commands",
|
|
2713
|
-
"missing_command_array",
|
|
2714
|
-
"qualityGate architectReview.commands must be a non-empty string array",
|
|
2861
|
+
found.check("architectReview.blockers", "non_empty_blockers", () =>
|
|
2862
|
+
requireEmptyBlockers(architectReview.blockers, "architectReview.blockers"),
|
|
2715
2863
|
);
|
|
2716
2864
|
}
|
|
2717
|
-
found.check("architectReview.evidence", "missing_evidence", () =>
|
|
2718
|
-
requireNonEmptyString(architectReview.evidence, "architectReview.evidence"),
|
|
2719
|
-
);
|
|
2720
|
-
found.check("architectReview.blockers", "non_empty_blockers", () =>
|
|
2721
|
-
requireEmptyBlockers(architectReview.blockers, "architectReview.blockers"),
|
|
2722
|
-
);
|
|
2723
2865
|
if (
|
|
2724
2866
|
executorQa.status !== PASSED_STATUS ||
|
|
2725
2867
|
executorQa.e2eStatus !== PASSED_STATUS ||
|
|
@@ -2763,7 +2905,9 @@ async function validateCompletionQualityGate(
|
|
|
2763
2905
|
found.check("iteration.blockers", "non_empty_blockers", () =>
|
|
2764
2906
|
requireEmptyBlockers(iteration.blockers, "iteration.blockers"),
|
|
2765
2907
|
);
|
|
2766
|
-
found.check("iteration.reviewCohort", "review_cohort_invalid", () =>
|
|
2908
|
+
found.check("iteration.reviewCohort", "review_cohort_invalid", () =>
|
|
2909
|
+
validateReviewCohort(gate, iteration, { lowRiskReduced }),
|
|
2910
|
+
);
|
|
2767
2911
|
if (batchMode && options.goal && options.plan && options.ledger) {
|
|
2768
2912
|
found.check("validationBatchClose", "batch_close_invalid", () =>
|
|
2769
2913
|
validateBatchCloseQualityGate(gate, options.plan!, batchMode, options.ledger!, options.changeSet),
|
|
@@ -3483,6 +3627,24 @@ export async function checkpointUltragoalGoal(input: {
|
|
|
3483
3627
|
: input.qualityGateJson
|
|
3484
3628
|
? await readStructuredValue(input.cwd, input.qualityGateJson)
|
|
3485
3629
|
: undefined;
|
|
3630
|
+
if (input.status === "complete" && !staleCompleteReceiptReplay) {
|
|
3631
|
+
// Validation consumes an asynchronous source snapshot. Re-capture directly
|
|
3632
|
+
// after it returns and require the authoritative digest to remain identical;
|
|
3633
|
+
// otherwise a concurrent edit could be committed against bytes that were not
|
|
3634
|
+
// the reviewed basis.
|
|
3635
|
+
const finalChangeSet = await computeCheckpointChangeSet(input.cwd);
|
|
3636
|
+
const initialSourceHash = computeUltragoalReviewSourceHash(changeSet);
|
|
3637
|
+
const finalSourceHash = computeUltragoalReviewSourceHash(finalChangeSet);
|
|
3638
|
+
if (
|
|
3639
|
+
((initialSourceHash || finalSourceHash) && initialSourceHash !== finalSourceHash) ||
|
|
3640
|
+
changeSet?.captureIncomplete ||
|
|
3641
|
+
finalChangeSet?.captureIncomplete
|
|
3642
|
+
) {
|
|
3643
|
+
throw new Error(
|
|
3644
|
+
"completion source changed or could not be captured consistently during validation; retry the checkpoint against a stable repository state",
|
|
3645
|
+
);
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3486
3648
|
const now = new Date().toISOString();
|
|
3487
3649
|
const beforeStatus = goal.status;
|
|
3488
3650
|
if (input.status === "complete") {
|
|
@@ -4212,28 +4374,6 @@ async function readOptionalExecutorQa(cwd: string, value: string | undefined): P
|
|
|
4212
4374
|
return structured as JsonObject;
|
|
4213
4375
|
}
|
|
4214
4376
|
|
|
4215
|
-
import {
|
|
4216
|
-
ciDevChangedPathRows,
|
|
4217
|
-
computeCheckpointChangeSet,
|
|
4218
|
-
mergeChangeSetPaths,
|
|
4219
|
-
parseGitNameStatus,
|
|
4220
|
-
parseGitUntrackedPaths,
|
|
4221
|
-
parseUnifiedDiffPaths,
|
|
4222
|
-
resolveGitBase,
|
|
4223
|
-
spawnText,
|
|
4224
|
-
} from "./ultragoal-change-set";
|
|
4225
|
-
|
|
4226
|
-
export {
|
|
4227
|
-
ciDevChangedPathRows,
|
|
4228
|
-
computeCheckpointChangeSet,
|
|
4229
|
-
mergeChangeSetPaths,
|
|
4230
|
-
parseGitNameStatus,
|
|
4231
|
-
parseGitUntrackedPaths,
|
|
4232
|
-
parseUnifiedDiffPaths,
|
|
4233
|
-
resolveGitBase,
|
|
4234
|
-
spawnText,
|
|
4235
|
-
};
|
|
4236
|
-
|
|
4237
4377
|
function changeSetFromReviewSource(source: JsonObject): UltragoalChangeSet | undefined {
|
|
4238
4378
|
const kind = nonEmptyString(source.kind);
|
|
4239
4379
|
if (kind === "spec") {
|
|
@@ -4722,6 +4862,7 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
|
|
|
4722
4862
|
"",
|
|
4723
4863
|
"USAGE",
|
|
4724
4864
|
" $ gjc ultragoal quality-gate init [--surface <name> ...] --out <path>",
|
|
4865
|
+
" $ gjc ultragoal quality-gate source-hash [--json]",
|
|
4725
4866
|
" $ gjc ultragoal quality-gate validate --quality-gate-json <json-or-path> [--goal-id <id>] [--json]",
|
|
4726
4867
|
"",
|
|
4727
4868
|
"FLAGS",
|
|
@@ -4733,6 +4874,7 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
|
|
|
4733
4874
|
"",
|
|
4734
4875
|
"EXAMPLES",
|
|
4735
4876
|
" $ gjc ultragoal quality-gate init --surface web --surface api --out ./quality-gate.json",
|
|
4877
|
+
" $ gjc ultragoal quality-gate source-hash --json",
|
|
4736
4878
|
" $ gjc ultragoal quality-gate validate --quality-gate-json ./quality-gate.json --json",
|
|
4737
4879
|
"",
|
|
4738
4880
|
].join("\n");
|
|
@@ -4756,6 +4898,8 @@ function renderUltragoalHelp(args: readonly string[]): string | null {
|
|
|
4756
4898
|
" record-critic-verdict",
|
|
4757
4899
|
" record-critic-gate-override",
|
|
4758
4900
|
" quality-gate init",
|
|
4901
|
+
" quality-gate source-hash",
|
|
4902
|
+
" quality-gate lane-selection",
|
|
4759
4903
|
" quality-gate validate",
|
|
4760
4904
|
|
|
4761
4905
|
"",
|
|
@@ -5141,6 +5285,57 @@ async function dispatchUltragoalCommand(
|
|
|
5141
5285
|
case "quality-gate": {
|
|
5142
5286
|
const positional = args.filter(arg => !arg.startsWith("-"));
|
|
5143
5287
|
const subcommand = positional[1];
|
|
5288
|
+
if (subcommand === "source-hash") {
|
|
5289
|
+
const changeSet = await computeCheckpointChangeSet(cwd);
|
|
5290
|
+
const sourceHash = computeUltragoalReviewSourceHash(changeSet);
|
|
5291
|
+
if (!sourceHash) {
|
|
5292
|
+
return {
|
|
5293
|
+
status: 1,
|
|
5294
|
+
stderr:
|
|
5295
|
+
"Unable to compute an authoritative source hash: change-set capture is incomplete, untrusted, or contains unknown-status paths.\n",
|
|
5296
|
+
};
|
|
5297
|
+
}
|
|
5298
|
+
const payload = {
|
|
5299
|
+
sourceHash,
|
|
5300
|
+
baseRef: changeSet?.baseRef,
|
|
5301
|
+
mergeBase: changeSet?.mergeBase,
|
|
5302
|
+
headRef: changeSet?.headRef,
|
|
5303
|
+
pathCount: changeSet?.paths.length ?? 0,
|
|
5304
|
+
};
|
|
5305
|
+
return json
|
|
5306
|
+
? { status: 0, stdout: `${JSON.stringify(payload, null, 2)}\n` }
|
|
5307
|
+
: { status: 0, stdout: `${sourceHash}\n` };
|
|
5308
|
+
}
|
|
5309
|
+
if (subcommand === "lane-selection") {
|
|
5310
|
+
// #4560: expose the authoritative computed selection so a caller can
|
|
5311
|
+
// declare `validationLaneSelection` without running or fabricating the
|
|
5312
|
+
// very lanes the selection may omit.
|
|
5313
|
+
const sessionId = currentUltragoalSessionId(cwd);
|
|
5314
|
+
const changeSet = await computeCheckpointChangeSet(cwd);
|
|
5315
|
+
const plan = await readUltragoalPlan(cwd, sessionId).catch(() => null);
|
|
5316
|
+
const ledger = await readUltragoalLedger(cwd, sessionId).catch(() => null);
|
|
5317
|
+
const authoritativeSourceHash = computeUltragoalReviewSourceHash(changeSet);
|
|
5318
|
+
const applicability = resolveUltragoalValidationApplicability({
|
|
5319
|
+
changeSet,
|
|
5320
|
+
requiredGoals: plan?.goals.filter(goal => goal.status !== "superseded").length,
|
|
5321
|
+
hasOpenReviewBlockers: plan?.goals.some(goal => goal.status === "review_blocked") ?? false,
|
|
5322
|
+
latestCohortSourceHash: ledger ? latestJoinedCohortSourceHash(ledger)?.sourceHash : undefined,
|
|
5323
|
+
currentSourceHash: authoritativeSourceHash ?? undefined,
|
|
5324
|
+
authoritativeSourceHash,
|
|
5325
|
+
});
|
|
5326
|
+
const laneSelection = validationLaneSelectionFor(applicability);
|
|
5327
|
+
const payload = {
|
|
5328
|
+
validationLaneSelection: laneSelection,
|
|
5329
|
+
basisUnchanged: applicability.basisUnchanged,
|
|
5330
|
+
sourceHash: authoritativeSourceHash,
|
|
5331
|
+
};
|
|
5332
|
+
return json
|
|
5333
|
+
? { status: 0, stdout: `${JSON.stringify(payload, null, 2)}\n` }
|
|
5334
|
+
: {
|
|
5335
|
+
status: 0,
|
|
5336
|
+
stdout: `riskClass=${applicability.riskClass} omittedLanes=${laneSelection.omittedLanes.join(",") || "(none)"}\n`,
|
|
5337
|
+
};
|
|
5338
|
+
}
|
|
5144
5339
|
if (subcommand === "init") {
|
|
5145
5340
|
const out = flagValue(args, "--out");
|
|
5146
5341
|
if (!out?.trim()) {
|
|
@@ -5164,7 +5359,7 @@ async function dispatchUltragoalCommand(
|
|
|
5164
5359
|
if (subcommand !== "validate") {
|
|
5165
5360
|
return {
|
|
5166
5361
|
status: 1,
|
|
5167
|
-
stderr: `Unknown gjc ultragoal quality-gate subcommand: ${subcommand ?? "(missing)"}; supported: init, validate\n`,
|
|
5362
|
+
stderr: `Unknown gjc ultragoal quality-gate subcommand: ${subcommand ?? "(missing)"}; supported: init, source-hash, lane-selection, validate\n`,
|
|
5168
5363
|
};
|
|
5169
5364
|
}
|
|
5170
5365
|
const qualityGateJson = flagValue(args, "--quality-gate-json");
|