@khoavu882/doflow 2.0.0-beta.5 → 2.0.1
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 +16 -16
- package/bin/doflow.js +22 -12
- package/core/.antigravity-plugin/plugin.json +1 -2
- package/core/.claude-plugin/plugin.json +1 -1
- package/core/.codex-plugin/plugin.json +1 -1
- package/core/.plugin/plugin.json +1 -1
- package/core/harnesses/claude/hooks/lib.sh +43 -24
- package/core/harnesses/claude/hooks/mcp-tool-guard.sh +4 -1
- package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
- package/core/harnesses/claude/hooks/post-compact.sh +35 -32
- package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
- package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
- package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
- package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
- package/core/harnesses/claude/hooks/pre-implement-gate.sh +4 -1
- package/core/harnesses/claude/hooks/session-end.sh +23 -10
- package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
- package/core/harnesses/claude/settings/settings.json +26 -9
- package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
- package/core/harnesses/codex/agents/core-implementer.toml +1 -0
- package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
- package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
- package/core/harnesses/codex/agents/research-writer.toml +1 -1
- package/core/harnesses/codex/agents/reviewer.toml +10 -0
- package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
- package/core/harnesses/codex/agents/system-architect.toml +1 -1
- package/core/harnesses/codex/hooks/hooks.json +0 -10
- package/core/harnesses/codex/hooks/lib.sh +44 -25
- package/core/harnesses/codex/hooks/mcp-tool-guard.sh +4 -1
- package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
- package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
- package/core/harnesses/codex/hooks/pre-implement-gate.sh +4 -1
- package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
- package/core/harnesses/codex/hooks/subagent-audit.sh +1 -0
- package/core/harnesses/copilot/hooks/doflow-lib.sh +94 -0
- package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
- package/core/harnesses/copilot/hooks/doflow.json +51 -0
- package/core/harnesses/kiro/agents/doflow.json +1 -11
- package/core/harnesses/kiro/hooks/doflow.json +0 -10
- package/core/harnesses/kiro/hooks/lib.sh +26 -6
- package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +8 -3
- package/core/harnesses/kiro/hooks/pre-implement-gate.sh +8 -3
- package/core/harnesses/kiro/hooks/session-start.sh +1 -0
- package/core/harnesses/kiro/hooks/stop-check.sh +1 -0
- package/core/harnesses/pi/extensions/doflow-guard.js +11 -2
- package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +1 -2
- package/core/harnesses/shared/hooks/adapters/antigravity.js +1 -1
- package/core/harnesses/shared/hooks/bridge/bridge.sh +126 -23
- package/core/harnesses/shared/hooks/bridge/envelope.jq +87 -18
- package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
- package/core/harnesses/shared/hooks/bridge/respond.sh +16 -2
- package/core/harnesses/shared/hooks/policies/capture-failure.sh +49 -16
- package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
- package/core/harnesses/shared/hooks/policies/contract.sh +3 -0
- package/core/harnesses/shared/hooks/policies/deny-json.sh +20 -7
- package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
- package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
- package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
- package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
- package/core/harnesses/shared/hooks/policies/lib.sh +63 -40
- package/core/harnesses/shared/hooks/policies/mcp-policy.conf +1 -1
- package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +7 -8
- package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +132 -57
- package/core/harnesses/shared/hooks/policies/session-context.sh +30 -1
- package/core/harnesses/shared/hooks/policies/stop-check.sh +27 -15
- package/core/harnesses/shared/hooks/policies/subagent-audit.sh +6 -3
- package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
- package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +60 -155
- package/core/harnesses/shared/hooks/stream-hook-runner.js +58 -20
- package/core/harnesses/shared/locator/doflow-run +2 -3
- package/core/registry/advice.json +3 -3
- package/core/registry/assets.json +55 -82
- package/core/registry/capabilities.json +12 -0
- package/core/registry/contracts.json +58 -31
- package/core/registry/contribution-points.json +35 -0
- package/core/registry/gates.json +32 -0
- package/core/registry/guidance-caps.json +40 -0
- package/core/registry/harnesses.json +1445 -366
- package/core/registry/intake.json +53 -0
- package/core/registry/lifecycle.json +599 -996
- package/core/registry/mcp.json +5 -1
- package/core/registry/models.json +7 -1
- package/core/registry/package-templates/README.md +19 -0
- package/core/registry/package-templates/agent/files/agent.md +9 -0
- package/core/registry/package-templates/agent/template.json +4 -0
- package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
- package/core/registry/package-templates/capability-provider/template.json +11 -0
- package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
- package/core/registry/package-templates/debate-preset/template.json +4 -0
- package/core/registry/package-templates/intake-category/files/category.json +8 -0
- package/core/registry/package-templates/intake-category/template.json +4 -0
- package/core/registry/package-templates/review-preset/files/preset.json +30 -0
- package/core/registry/package-templates/review-preset/template.json +4 -0
- package/core/registry/package-templates/skill/files/SKILL.md +8 -0
- package/core/registry/package-templates/skill/template.json +4 -0
- package/core/registry/package-templates/worker/files/worker.json +92 -0
- package/core/registry/package-templates/worker/template.json +11 -0
- package/core/registry/packages/doflow/doflow-package.json +15 -0
- package/core/registry/packages/doflow/presets/debate-3.json +26 -0
- package/core/registry/protocols.json +61 -0
- package/core/registry/routes.json +17 -0
- package/core/registry/rules.json +431 -0
- package/core/registry/settings.json +272 -0
- package/core/registry/storage.json +687 -31
- package/core/registry/telemetry.json +236 -0
- package/core/registry/transcripts.json +142 -0
- package/core/registry/verification.json +76 -6
- package/core/registry/workflows.json +55 -0
- package/core/shared/agent-specs/core-implementer.md +3 -0
- package/core/shared/agent-specs/delivery-lead.md +68 -0
- package/core/shared/agent-specs/quality-guardian.md +5 -1
- package/core/shared/agent-specs/research-writer.md +10 -3
- package/core/shared/agent-specs/reviewer.md +53 -0
- package/core/shared/agent-specs/spec-analyst.md +5 -6
- package/core/shared/agent-specs/system-architect.md +5 -1
- package/core/shared/guidance/DOFLOW_CORE.md +1 -5
- package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
- package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
- package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
- package/core/shared/guidance/pointers/codex.md +1 -4
- package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
- package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
- package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
- package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
- package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
- package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
- package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
- package/core/shared/guidance/references/ORCHESTRATION.md +3 -2
- package/core/shared/guidance/references/WORKFLOW_HANDOFF.md +19 -1
- package/core/shared/guidance/rules/RULES.md +45 -0
- package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
- package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
- package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
- package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
- package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
- package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
- package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
- package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
- package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
- package/core/shared/scripts/doflow/bash/validate-artifacts.sh +49 -5
- package/core/shared/scripts/doflow/bin/doflow-run +152 -34
- package/core/shared/skills/do/SKILL.md +14 -12
- package/core/shared/skills/do/references/advice_calls.md +26 -0
- package/core/shared/skills/do/references/pm_routing.md +1 -2
- package/core/shared/skills/do/references/program_mode.md +31 -0
- package/core/shared/skills/do-brainstorm/SKILL.md +45 -97
- package/core/shared/skills/do-brainstorm/references/handoff_branches.md +36 -0
- package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
- package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
- package/core/shared/skills/do-code-review/SKILL.md +48 -148
- package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
- package/core/shared/skills/do-code-review/references/tools.md +90 -0
- package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
- package/core/shared/skills/do-design/SKILL.md +23 -20
- package/core/shared/skills/do-diagnose/SKILL.md +18 -6
- package/core/shared/skills/do-document/SKILL.md +12 -1
- package/core/shared/skills/do-document/references/deep_research.md +1 -2
- package/core/shared/skills/do-document/references/embedded-research.md +19 -7
- package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
- package/core/shared/skills/do-execute-plan/SKILL.md +19 -60
- package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
- package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
- package/core/shared/skills/do-execute-plan/references/readiness_gate.md +26 -1
- package/core/shared/skills/do-execute-plan/references/run_position.md +16 -2
- package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
- package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
- package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
- package/core/shared/skills/do-flow/SKILL.md +10 -11
- package/core/shared/skills/do-flow/references/task_classes.md +5 -5
- package/core/shared/skills/do-git/SKILL.md +4 -0
- package/core/shared/skills/do-implement/SKILL.md +13 -14
- package/core/shared/skills/do-plan/SKILL.md +34 -20
- package/core/shared/skills/do-test/SKILL.md +7 -4
- package/core/shared/templates/doflow/constitution-template.md +9 -3
- package/core/shared/templates/doflow/data-model-template.md +1 -1
- package/core/shared/templates/doflow/design-template.md +113 -16
- package/core/shared/templates/doflow/plan-template.md +11 -10
- package/core/shared/templates/doflow/question-log-template.md +14 -2
- package/core/shared/templates/doflow/requirement-template.md +1 -1
- package/core/shared/workflows/do-flow-chain.md +2 -0
- package/core/worker-evidence/antigravity/checks.json +14 -0
- package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
- package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
- package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
- package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
- package/core/worker-evidence/codex/checks.json +38 -0
- package/package.json +10 -6
- package/src/adapters/antigravity/index.js +143 -66
- package/src/adapters/claude/index.js +46 -5
- package/src/adapters/codex/agents.js +25 -15
- package/src/adapters/codex/hooks.js +39 -3
- package/src/adapters/codex/index.js +61 -13
- package/src/adapters/codex/native-projection.js +6 -2
- package/src/adapters/copilot/index.js +58 -23
- package/src/adapters/copy-tree.js +291 -46
- package/src/adapters/guidance-manifest.js +71 -0
- package/src/adapters/guidance-pointer.js +19 -0
- package/src/adapters/hook-commands.js +6 -10
- package/src/adapters/index.js +1 -0
- package/src/adapters/kiro/index.js +23 -12
- package/src/adapters/opencode/index.js +8 -8
- package/src/adapters/pi/hooks.js +2 -1
- package/src/adapters/pi/index.js +14 -7
- package/src/adapters/resolve-source.js +26 -2
- package/src/cli/commands/install.js +2 -1
- package/src/cli/commands/reconcile.js +53 -9
- package/src/cli/commands/remove.js +2 -2
- package/src/cli/commands/rollback.js +6 -3
- package/src/cli/commands/self-update.js +18 -9
- package/src/cli/commands/status.js +22 -3
- package/src/cli/commands/ui.js +99 -0
- package/src/cli/commands/update.js +2 -1
- package/src/cli/index.js +337 -32
- package/src/cli/runtime-commands.js +220 -60
- package/src/cli/shared.js +0 -2
- package/src/helper/git.js +1 -1
- package/src/helper/guardrails.js +1 -1
- package/src/helper/marker-merge.js +31 -13
- package/src/helper/package-ids.js +37 -0
- package/src/helper/semver.js +94 -0
- package/src/install/backup.js +105 -15
- package/src/install/context.js +1 -1
- package/src/install/targets.js +31 -16
- package/src/lifecycle/coverage.js +4 -16
- package/src/lifecycle/hook-tier.js +160 -0
- package/src/lifecycle/index.js +412 -78
- package/src/lifecycle/retired-harnesses.js +318 -0
- package/src/lifecycle/view.js +35 -15
- package/src/registry/index.js +551 -26
- package/src/registry/worker-ids.js +45 -0
- package/src/release/build-package.js +0 -3
- package/src/release/docs-blocks.js +472 -0
- package/src/release/preflight.js +425 -0
- package/src/release/rehearse.js +401 -0
- package/src/release/release-workflow.js +733 -0
- package/src/release/sync-plugin-versions.js +43 -7
- package/src/runtime/advice/bench-gate.js +25 -0
- package/src/runtime/advice/cli.js +59 -16
- package/src/runtime/advice/client.js +32 -9
- package/src/runtime/advice/config.js +98 -133
- package/src/runtime/advice/doctor.js +1 -1
- package/src/runtime/advice/elevation.js +97 -0
- package/src/runtime/advice/endpoint-guard.js +9 -3
- package/src/runtime/advice/mode.js +37 -0
- package/src/runtime/advice/record.js +18 -5
- package/src/runtime/advice/registry.js +4 -1
- package/src/runtime/advice/shadow-config.js +229 -0
- package/src/runtime/advice/shadow-dispatcher.js +276 -0
- package/src/runtime/brief-rules.js +81 -0
- package/src/runtime/brief-tools.js +111 -34
- package/src/runtime/candidate.js +20 -11
- package/src/runtime/capabilities/executor.js +450 -0
- package/src/runtime/capabilities/loopback.js +41 -0
- package/src/runtime/capabilities/sanitizer.js +88 -0
- package/src/runtime/capability-router.js +135 -3
- package/src/runtime/checkouts.js +73 -11
- package/src/runtime/claims.js +13 -7
- package/src/runtime/cli.js +196 -19
- package/src/runtime/config-home.js +42 -0
- package/src/runtime/context/arbitrate.js +767 -0
- package/src/runtime/context/delivery-store.js +4 -6
- package/src/runtime/context/emission-rules.js +118 -0
- package/src/runtime/context/identity.js +227 -0
- package/src/runtime/context/pointer.js +67 -12
- package/src/runtime/context/primary-command.js +117 -0
- package/src/runtime/context/primary.js +344 -0
- package/src/runtime/context/summary-store.js +655 -0
- package/src/runtime/context-pack.js +158 -79
- package/src/runtime/decision-register.js +13 -4
- package/src/runtime/dispatch/admission.js +392 -0
- package/src/runtime/dispatch/attempt-end.js +274 -0
- package/src/runtime/dispatch/command.js +628 -0
- package/src/runtime/dispatch/controls.js +904 -0
- package/src/runtime/dispatch/envelope.js +276 -0
- package/src/runtime/dispatch/grants.js +310 -0
- package/src/runtime/dispatch/integrate.js +617 -0
- package/src/runtime/dispatch/loop.js +1835 -0
- package/src/runtime/dispatch/store.js +352 -0
- package/src/runtime/dispatch/verify-run.js +201 -0
- package/src/runtime/evidence-ledger.js +52 -7
- package/src/runtime/failure/capture.js +3 -1
- package/src/runtime/failure/cli.js +25 -9
- package/src/runtime/failure/home.js +57 -30
- package/src/runtime/failure/store.js +7 -2
- package/src/runtime/feature-pointer.js +174 -0
- package/src/runtime/feature-resolve.js +13 -2
- package/src/runtime/fleet/command.js +77 -0
- package/src/runtime/fleet/projects.js +178 -0
- package/src/runtime/fleet/tree.js +383 -0
- package/src/runtime/freshness.js +33 -3
- package/src/runtime/git-memo.js +46 -0
- package/src/runtime/guidance/ablation.js +427 -0
- package/src/runtime/health.js +624 -18
- package/src/runtime/history-compactor.js +13 -3
- package/src/runtime/implementation-gate.js +281 -26
- package/src/runtime/intake/engine.js +677 -0
- package/src/runtime/intake/index.js +136 -0
- package/src/runtime/intake/manifest.js +140 -0
- package/src/runtime/intake/taxonomy.js +206 -0
- package/src/runtime/inventory/coverage.js +1 -1
- package/src/runtime/inventory/index.js +1 -1
- package/src/runtime/inventory/precedence.js +2 -2
- package/src/runtime/inventory/siblings.js +6 -4
- package/src/runtime/knowledge/code-corpus.js +277 -0
- package/src/runtime/knowledge/code-lexical.js +130 -0
- package/src/runtime/knowledge/code-retrieval.js +307 -0
- package/src/runtime/knowledge/code-validation.js +106 -0
- package/src/runtime/knowledge/gp3-gate.js +74 -0
- package/src/runtime/knowledge/graph-adapter.js +288 -0
- package/src/runtime/knowledge/graph-fallback.js +394 -0
- package/src/runtime/knowledge/hybrid.js +136 -8
- package/src/runtime/knowledge/retrieval.js +34 -1
- package/src/runtime/knowledge/rtk-compress.js +77 -0
- package/src/runtime/knowledge/semble-bridge.py +106 -0
- package/src/runtime/knowledge/semble-lifecycle.js +114 -0
- package/src/runtime/knowledge/semble-provider.js +365 -0
- package/src/runtime/lifecycle/cli.js +88 -10
- package/src/runtime/lifecycle/event-store.js +8 -6
- package/src/runtime/lifecycle/followup.js +38 -7
- package/src/runtime/lifecycle/overview.js +26 -2
- package/src/runtime/lifecycle/report-store.js +8 -10
- package/src/runtime/lifecycle/retention.js +95 -31
- package/src/runtime/lifecycle/root.js +9 -1
- package/src/runtime/lifecycle/status.js +34 -17
- package/src/runtime/lifecycle/store-upkeep.js +56 -7
- package/src/runtime/mask.js +134 -7
- package/src/runtime/mcp-consultations.js +40 -6
- package/src/runtime/model-router.js +79 -7
- package/src/runtime/models/catalogue.js +191 -0
- package/src/runtime/models/command.js +153 -0
- package/src/runtime/off-words.js +12 -0
- package/src/runtime/outcome.js +2 -2
- package/src/runtime/packages/command.js +1009 -0
- package/src/runtime/packages/contributions.js +116 -0
- package/src/runtime/packages/digest.js +132 -0
- package/src/runtime/packages/fetch.js +182 -0
- package/src/runtime/packages/grants.js +192 -0
- package/src/runtime/packages/index-file.js +134 -0
- package/src/runtime/packages/instruction.js +90 -0
- package/src/runtime/packages/manifest.js +331 -0
- package/src/runtime/packages/points.js +487 -0
- package/src/runtime/packages/programs.js +216 -0
- package/src/runtime/packages/scaffold.js +277 -0
- package/src/runtime/packages/source.js +90 -0
- package/src/runtime/packages/state.js +164 -0
- package/src/runtime/packages/store.js +449 -0
- package/src/runtime/packages/tar.js +106 -0
- package/src/runtime/packages/view.js +406 -0
- package/src/runtime/plan-check.js +59 -0
- package/src/runtime/plan-content.js +324 -0
- package/src/runtime/policy-init.js +118 -0
- package/src/runtime/profiles/doctor.js +96 -0
- package/src/runtime/profiles/resolve.js +244 -0
- package/src/runtime/profiles/rollback.js +254 -0
- package/src/runtime/profiles/sampler.js +41 -0
- package/src/runtime/readiness-record.js +16 -11
- package/src/runtime/readiness.js +46 -5
- package/src/runtime/research-request.js +50 -25
- package/src/runtime/retrieval-plan.js +10 -30
- package/src/runtime/retrieval-record.js +75 -5
- package/src/runtime/review/command.js +246 -0
- package/src/runtime/review/dominance.js +68 -0
- package/src/runtime/review/findings.js +434 -0
- package/src/runtime/review/identity.js +255 -0
- package/src/runtime/review/protocol-command.js +109 -0
- package/src/runtime/review/protocols.js +405 -0
- package/src/runtime/review/resolve-protocol.js +302 -0
- package/src/runtime/review/start.js +530 -0
- package/src/runtime/roadmap/attendance.js +137 -0
- package/src/runtime/roadmap/facts.js +479 -0
- package/src/runtime/roadmap/gates.js +273 -0
- package/src/runtime/roadmap/loop.js +1719 -0
- package/src/runtime/roadmap/merge.js +390 -0
- package/src/runtime/roadmap/rows.js +1122 -0
- package/src/runtime/roadmap/seed.js +1063 -0
- package/src/runtime/roadmap/worktree-cleanup.js +147 -0
- package/src/runtime/rules-report.js +336 -0
- package/src/runtime/scaffold/artifacts.js +60 -9
- package/src/runtime/scaffold/generate.js +21 -9
- package/src/runtime/settings/autopilot.js +106 -0
- package/src/runtime/settings/cli.js +280 -0
- package/src/runtime/settings/config-write.js +314 -0
- package/src/runtime/settings/files.js +271 -0
- package/src/runtime/settings/legacy.js +154 -0
- package/src/runtime/settings/lexical.js +56 -0
- package/src/runtime/settings/prepared-run.js +269 -0
- package/src/runtime/settings/project-layers.js +118 -0
- package/src/runtime/settings/refs.js +288 -0
- package/src/runtime/settings/registry.js +553 -0
- package/src/runtime/settings/resolve.js +713 -0
- package/src/runtime/settings/shared.js +37 -0
- package/src/runtime/settings/worker-billing.js +107 -0
- package/src/runtime/settings/write.js +269 -0
- package/src/runtime/slot-command.js +78 -0
- package/src/runtime/slots.js +671 -0
- package/src/runtime/source-version.js +1 -0
- package/src/runtime/state-root.js +217 -0
- package/src/runtime/storage/cli.js +12 -5
- package/src/runtime/storage/engine.js +9 -2
- package/src/runtime/storage/registry.js +14 -1
- package/src/runtime/storage/roots.js +66 -16
- package/src/runtime/storage/rules.js +82 -10
- package/src/runtime/storage/upkeep.js +10 -2
- package/src/runtime/storage/work-status.js +245 -26
- package/src/runtime/task-attempts.js +589 -69
- package/src/runtime/task-classifier.js +85 -14
- package/src/runtime/task-graph.js +373 -0
- package/src/runtime/task-run.js +778 -0
- package/src/runtime/task-scope.js +176 -55
- package/src/runtime/task-sources.js +147 -0
- package/src/runtime/task-state.js +373 -64
- package/src/runtime/team/admission.js +301 -0
- package/src/runtime/team/envelope.js +324 -0
- package/src/runtime/team/review-guard.js +156 -0
- package/src/runtime/trace/analyze.js +427 -0
- package/src/runtime/trace/baseline.js +770 -0
- package/src/runtime/trace/ledger.js +63 -140
- package/src/runtime/trace/otlp-export.js +568 -0
- package/src/runtime/trace/otlp-map.js +481 -0
- package/src/runtime/trace/spans.js +745 -0
- package/src/runtime/trace/telemetry.js +225 -0
- package/src/runtime/trace/views.js +1 -0
- package/src/runtime/transcripts/command.js +98 -0
- package/src/runtime/transcripts/cursor.js +326 -0
- package/src/runtime/transcripts/read.js +126 -0
- package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
- package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
- package/src/runtime/transcripts/readers/copilot-events.js +90 -0
- package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
- package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
- package/src/runtime/transcripts/registry.js +161 -0
- package/src/runtime/transcripts/stats.js +161 -0
- package/src/runtime/verb-view.js +267 -0
- package/src/runtime/verification/check-key.js +628 -0
- package/src/runtime/verification/contract-runner.js +546 -11
- package/src/runtime/verification/engine.js +499 -54
- package/src/runtime/verification/impact.js +617 -0
- package/src/runtime/verification/inflight.js +205 -0
- package/src/runtime/verification/registry.js +176 -0
- package/src/runtime/verification/reuse.js +184 -0
- package/src/runtime/verification/telemetry-emit.js +254 -0
- package/src/runtime/verification/test-selection.js +67 -7
- package/src/runtime/worker/active.js +90 -0
- package/src/runtime/worker/cancel.js +222 -0
- package/src/runtime/worker/catalogue.js +122 -0
- package/src/runtime/worker/command.js +677 -0
- package/src/runtime/worker/evidence.js +288 -0
- package/src/runtime/worker/launch.js +256 -0
- package/src/runtime/worker/models.js +137 -0
- package/src/runtime/worker/parsers.js +218 -0
- package/src/runtime/worker/probes/index.js +706 -0
- package/src/runtime/worker/process-tree.js +415 -0
- package/src/runtime/worker/quota.js +43 -0
- package/src/runtime/worker/readiness.js +713 -0
- package/src/runtime/worker/run-store.js +166 -0
- package/src/runtime/worker/supervisor.js +541 -0
- package/src/runtime/worker/worktree-check.js +252 -0
- package/src/runtime/workflow-engine.js +5 -1
- package/src/runtime/workflow-orchestrator.js +610 -67
- package/src/runtime/worktree.js +149 -22
- package/src/state/index.js +1 -1
- package/src/state/lockfile.js +64 -10
- package/src/state/run-lock.js +1 -1
- package/types/node-commonjs.d.ts +106 -7
- package/core/harnesses/claude/hooks/pre-bash-guard.sh +0 -10
- package/core/harnesses/codex/hooks/pre-bash-guard.sh +0 -10
- package/core/harnesses/gemini/hooks/hooks.json +0 -77
- package/core/harnesses/gemini/hooks/lib.sh +0 -302
- package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -10
- package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
- package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -10
- package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
- package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -10
- package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
- package/core/harnesses/gemini/hooks/session-end.sh +0 -5
- package/core/harnesses/gemini/hooks/session-start.sh +0 -7
- package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
- package/core/harnesses/kiro/hooks/pre-bash-guard.sh +0 -24
- package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +0 -91
- package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +0 -378
- package/core/shared/guidance/FLAGS.md +0 -25
- package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
- package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
- package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
- package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
- package/src/adapters/gemini/hooks.js +0 -251
- package/src/adapters/gemini/index.js +0 -429
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// 119 IC-003: the pure protocol resolver. Given the change facts (class, risk, changed paths), the run's
|
|
4
|
+
// preset and the loaded registries, it picks the review or debate protocol and says where each value came
|
|
5
|
+
// from. No filesystem, git or process: the caller loads the inputs (start.ts `loadProtocolInputs`), the
|
|
6
|
+
// settings among them as a plain `settingsView` ({ '<key>': { value, layer } }, an absent key = default).
|
|
7
|
+
|
|
8
|
+
const nodeCrypto = require('node:crypto');
|
|
9
|
+
const { presetIds, coreTiers } = require('./protocols.js');
|
|
10
|
+
const { dominates } = require('./dominance.js');
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
const DEBATE_DEFAULT = 'debate-2';
|
|
16
|
+
|
|
17
|
+
/** Whether `riskPolicy.lightPaths` covers `file`: a `/`-ending entry covers its subtree, any other entry that exact path. */
|
|
18
|
+
function lightCovers(lightPaths , file ) {
|
|
19
|
+
const normal = String(file).replace(/^(\.\/)+/, '');
|
|
20
|
+
return lightPaths.some((entry) => (entry.endsWith('/') ? normal.startsWith(entry) : normal === entry));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The scope of a change: `light` when every path is covered by `lightPaths`, `code` otherwise, `unknown` when
|
|
25
|
+
* the list is unreadable (null) or empty (the base resolved to HEAD; the verb does not know what the review covers).
|
|
26
|
+
* A rename is two entries, so it counts both paths.
|
|
27
|
+
*/
|
|
28
|
+
function pathScope(riskPolicy , paths ) {
|
|
29
|
+
if (!Array.isArray(paths) || paths.length === 0) return 'unknown';
|
|
30
|
+
return paths.every((file) => lightCovers(riskPolicy.lightPaths, file)) ? 'light' : 'code';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** The gate-b `minSeats` of a class from a loaded gate policy; 0 when there is none. */
|
|
34
|
+
function gateMinSeats(gatePolicy , taskClass ) {
|
|
35
|
+
if (!gatePolicy || !taskClass) return 0;
|
|
36
|
+
const floor = gatePolicy.classes?.[taskClass]?.['gate-b']?.minSeats;
|
|
37
|
+
return Number.isInteger(floor) && floor > 0 ? floor : 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* 119 FR-008: one `{ agent, harness, status, reason }` row per read-only seat agent (seat order, each once) x harness
|
|
42
|
+
* (registry order). `agentAccess` is `{ <agent>: 'read-only'|'write'|'unknown' }`, `readOnlyLimits` the ordered
|
|
43
|
+
* `[{ harness, status, reason }]` the caller loaded; a caller that passes neither gets no rows. An agent whose access
|
|
44
|
+
* is unknown (absent counts as unknown) gets rows too, `status: unknown` with the reason, so a seat whose access the
|
|
45
|
+
* runtime cannot read is reported as such rather than dropped like a write agent.
|
|
46
|
+
*/
|
|
47
|
+
function enforcementRows(seats , agentAccess , readOnlyLimits ) {
|
|
48
|
+
if (!agentAccess || !Array.isArray(readOnlyLimits)) return [];
|
|
49
|
+
const access = (agent ) => (agentAccess[agent] === 'read-only' || agentAccess[agent] === 'write' ? agentAccess[agent] : 'unknown');
|
|
50
|
+
const agents = [...new Set (seats.map((seat ) => seat.agent))].filter((agent) => access(agent) !== 'write');
|
|
51
|
+
return agents.flatMap((agent) => readOnlyLimits.map((limit ) => (access(agent) === 'read-only'
|
|
52
|
+
? { agent, harness: limit.harness, status: limit.status, reason: limit.reason ?? null }
|
|
53
|
+
: { agent, harness: limit.harness, status: 'unknown', reason: `the access of agent '${agent}' is not declared in core/registry/workflows.json agents.access` })));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** The review preset id carrying a depth label, or undefined. */
|
|
57
|
+
function idOfDepth(registry , depth ) {
|
|
58
|
+
return presetIds(registry, 'review').find((id ) => registry.presets[id].depth === depth);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** The preset `id` of `kind` in the merged registry (core or an active package's), or null when it is not available. */
|
|
62
|
+
function presetOf(registry , kind , id ) {
|
|
63
|
+
return typeof id === 'string' && Object.hasOwn(registry.presets ?? {}, id) && registry.presets[id]?.kind === kind ? registry.presets[id] : null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* 122 IC-014: true when the available preset `a` is at least as strict as `b`, both of `kind`. Two ids of the effective
|
|
68
|
+
* core order compare by their place in it; any other pair (a contributed id on either side) by `dominates`, so no
|
|
69
|
+
* `indexOf` of -1 is ever read as a rank. An id that is not available is never at least as strict.
|
|
70
|
+
*/
|
|
71
|
+
function atLeastAsStrict(registry , kind , a , b ) {
|
|
72
|
+
const order = presetIds(registry, kind);
|
|
73
|
+
if (order.includes(a) && order.includes(b)) return order.indexOf(a) <= order.indexOf(b);
|
|
74
|
+
const pa = presetOf(registry, kind, a);
|
|
75
|
+
const pb = presetOf(registry, kind, b);
|
|
76
|
+
return pa !== null && pb !== null && dominates(pa, pb, { tiers: coreTiers(), synthesizerStrength: registry.synthesizerStrength });
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The setting `key` from a settings view when a non-default layer set it, else null. */
|
|
80
|
+
function setBy(settingsView , key ) {
|
|
81
|
+
const entry = settingsView?.[key];
|
|
82
|
+
return entry && entry.layer !== undefined && entry.layer !== 'default' ? entry : null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* IC-003 step 2, shared with the prepared-run check (119 C-3): the preset setting applied to a `pick`
|
|
87
|
+
* (`{ id, origin }`). `auto` and the default leave the pick; a stricter id is taken with its layer
|
|
88
|
+
* as origin; an equal one changes nothing, except that a debate (whose pick is the registry default) then names
|
|
89
|
+
* the layer that decided it (C-11); a looser one is ignored and returned as `disagreement`. 122 IC-014: an id that is
|
|
90
|
+
* not available (unknown, or its package disabled, suspended or incompatible) leaves the pick with the disagreement
|
|
91
|
+
* `unavailable`; a contributed id is taken only when it dominates the pick, else `not-dominant`. Pure apart from the
|
|
92
|
+
* core tiers a dominance comparison reads (models.json, once per process).
|
|
93
|
+
*/
|
|
94
|
+
function settingsPick({ kind, pick, settingsView, registry } )
|
|
95
|
+
{
|
|
96
|
+
const order = presetIds(registry, kind);
|
|
97
|
+
const preset = setBy(settingsView, kind === 'review' ? 'review.preset' : 'debate.preset');
|
|
98
|
+
if (!preset || typeof preset.value !== 'string' || preset.value === 'auto') return { ...pick };
|
|
99
|
+
if (presetOf(registry, kind, preset.value) === null) {
|
|
100
|
+
return { ...pick, disagreement: { field: 'id', by: preset.layer, value: preset.value, reason: 'unavailable' } };
|
|
101
|
+
}
|
|
102
|
+
if (!order.includes(preset.value) || !order.includes(pick.id)) {
|
|
103
|
+
return atLeastAsStrict(registry, kind, preset.value, pick.id) ? { id: preset.value, origin: preset.layer }
|
|
104
|
+
: { ...pick, disagreement: { field: 'id', by: preset.layer, value: preset.value, reason: 'not-dominant' } };
|
|
105
|
+
}
|
|
106
|
+
const at = order.indexOf(preset.value);
|
|
107
|
+
const from = order.indexOf(pick.id);
|
|
108
|
+
if (at < from || (at === from && kind === 'debate')) return { id: preset.value, origin: preset.layer };
|
|
109
|
+
if (at > from) return { ...pick, disagreement: { field: 'id', by: preset.layer, value: preset.value, reason: 'looser' } };
|
|
110
|
+
return { ...pick };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* IC-003, in this order: (1) the start pick (the risk rule under `auto`, else the thin default), (2) the preset setting, (3) the run preset (Q-A1: compared with the
|
|
115
|
+
* pick of steps 1-2; advice raises only when there is no run preset), (4) advice, (5) the seat floor, (6) the knobs
|
|
116
|
+
* of a review. A setting is never a refusal: a looser preset setting is ignored and listed in `disagreements`.
|
|
117
|
+
* Returns `{ ok: true, protocol }` or `{ ok: false, reason, field }`.
|
|
118
|
+
*/
|
|
119
|
+
function resolveProtocol({ kind, taskClass, risk, paths, runPreset, advicePick, settingsView, gatePolicy, unattended, registry, riskPolicy, agentAccess, readOnlyLimits } )
|
|
120
|
+
{
|
|
121
|
+
const order = presetIds(registry, kind);
|
|
122
|
+
const disagreements = [];
|
|
123
|
+
let id ;
|
|
124
|
+
let idOrigin = 'registry';
|
|
125
|
+
|
|
126
|
+
// Step 1 (maint-thin): a review starts thin. Only an effective `review.preset` of `auto` runs the risk rule (as the
|
|
127
|
+
// old decideDepth did); otherwise the pick starts at the default-layer preset (the registry default, review-single)
|
|
128
|
+
// or, with no entry at all, the loosest core preset, and step 2 raises it to a stricter preset a layer set. A preset
|
|
129
|
+
// id this install does not have never reaches here from a run: loadProtocolInputs refuses it (settings-unavailable),
|
|
130
|
+
// so the review is blocked, which fails closed. A debate starts at debate-2.
|
|
131
|
+
if (kind === 'review') {
|
|
132
|
+
const entry = settingsView?.['review.preset'];
|
|
133
|
+
if (entry?.value === 'auto') {
|
|
134
|
+
const single = pathScope(riskPolicy, paths) === 'light' && typeof risk === 'string' && riskPolicy.singleRisks.includes(risk);
|
|
135
|
+
id = idOfDepth(registry, single ? 'single' : 'deep');
|
|
136
|
+
idOrigin = 'risk';
|
|
137
|
+
} else {
|
|
138
|
+
const shipped = entry && !setBy(settingsView, 'review.preset') && typeof entry.value === 'string' && order.includes(entry.value) ? entry.value : undefined;
|
|
139
|
+
id = shipped ?? order[order.length - 1];
|
|
140
|
+
}
|
|
141
|
+
} else id = DEBATE_DEFAULT;
|
|
142
|
+
if (id === undefined || !order.includes(id)) return { ok: false, reason: 'registry-incomplete', field: 'registry' };
|
|
143
|
+
|
|
144
|
+
// Step 2: the preset setting (settingsPick).
|
|
145
|
+
const picked = settingsPick({ kind, pick: { id, origin: idOrigin }, settingsView, registry });
|
|
146
|
+
// The core pick of steps 1-2: what the seat floor falls back to when a contributed pick has too few seats (IC-014).
|
|
147
|
+
const corePick = order.includes(picked.id) ? picked.id : id;
|
|
148
|
+
id = picked.id;
|
|
149
|
+
idOrigin = picked.origin;
|
|
150
|
+
if (picked.disagreement) disagreements.push(picked.disagreement);
|
|
151
|
+
|
|
152
|
+
// Advice only raises: a deep pick over a single pick gives deep.
|
|
153
|
+
const adviceId = kind === 'review' && advicePick === 'deep' && registry.presets[id].depth === 'single'
|
|
154
|
+
? idOfDepth(registry, 'deep') : undefined;
|
|
155
|
+
|
|
156
|
+
// Step 3: the run preset must exist for this kind and be at least as strict as the pick of steps 1-2 (a contributed
|
|
157
|
+
// one: dominate it). It wins over advice (Q-A1): an advice raise above it is not applied and is shown as a disagreement.
|
|
158
|
+
if (runPreset !== undefined && runPreset !== null) {
|
|
159
|
+
if (typeof runPreset !== 'string' || presetOf(registry, kind, runPreset) === null) return { ok: false, reason: 'preset-unknown', field: 'preset' };
|
|
160
|
+
if (!atLeastAsStrict(registry, kind, runPreset, id)) return { ok: false, reason: 'preset-looser', field: 'preset' };
|
|
161
|
+
id = runPreset;
|
|
162
|
+
idOrigin = 'run';
|
|
163
|
+
if (adviceId !== undefined && !atLeastAsStrict(registry, kind, runPreset, adviceId)) {
|
|
164
|
+
disagreements.push({ field: 'id', by: 'advice', value: adviceId, reason: 'run-preset' });
|
|
165
|
+
}
|
|
166
|
+
} else if (adviceId !== undefined) {
|
|
167
|
+
id = adviceId;
|
|
168
|
+
idOrigin = 'advice';
|
|
169
|
+
}
|
|
170
|
+
// Step 5: the class seat floor. A pick with fewer seats takes the next stricter preset that has enough;
|
|
171
|
+
// when none has, the strictest preset gains copies of its last seat (L-4). The walk reads the core order only: a
|
|
172
|
+
// contributed pick with too few seats first falls back to the core pick of steps 1-2 (IC-014), with a disagreement.
|
|
173
|
+
let seats = registry.presets[id].seats.map((seat ) => structuredClone(seat));
|
|
174
|
+
let seatsOrigin = 'registry';
|
|
175
|
+
// maint-thin: the class floor binds only a review nobody attends (`unattended`: the autopilot switch is on, so its
|
|
176
|
+
// policy gate-b may decide the merge); a person-attended review follows the preset. Omitted reads as unattended.
|
|
177
|
+
const needed = kind === 'review' && unattended !== false ? gateMinSeats(gatePolicy, taskClass) : 0;
|
|
178
|
+
if (seats.length < needed && !order.includes(id)) {
|
|
179
|
+
disagreements.push({ field: 'id', by: 'floor', value: id, reason: 'seat-floor' });
|
|
180
|
+
id = corePick;
|
|
181
|
+
idOrigin = 'floor';
|
|
182
|
+
seats = registry.presets[id].seats.map((seat ) => structuredClone(seat));
|
|
183
|
+
}
|
|
184
|
+
if (seats.length < needed) {
|
|
185
|
+
const stricter = order.slice(0, order.indexOf(id)).reverse().find((candidate) => registry.presets[candidate].seats.length >= needed);
|
|
186
|
+
idOrigin = 'floor';
|
|
187
|
+
if (stricter !== undefined) {
|
|
188
|
+
id = stricter;
|
|
189
|
+
seats = registry.presets[id].seats.map((seat ) => structuredClone(seat));
|
|
190
|
+
} else {
|
|
191
|
+
id = order[0];
|
|
192
|
+
seats = registry.presets[id].seats.map((seat ) => structuredClone(seat));
|
|
193
|
+
while (seats.length < needed) seats.push({ ...structuredClone(seats[seats.length - 1]), id: `floor-${seats.length + 1}` });
|
|
194
|
+
seatsOrigin = 'floor';
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const chosen = registry.presets[id];
|
|
199
|
+
const protocol = { id, kind };
|
|
200
|
+
if (kind === 'review' && chosen.depth !== undefined) protocol.depth = chosen.depth; // a contributed preset has no depth label
|
|
201
|
+
|
|
202
|
+
// Step 6: the knobs of a review, applied to the final preset. A debate keeps its preset's values.
|
|
203
|
+
let rounds = chosen.rounds.default;
|
|
204
|
+
let roundsOrigin = 'registry';
|
|
205
|
+
let lensesOrigin = 'registry';
|
|
206
|
+
let blockersOrigin = 'registry';
|
|
207
|
+
let sameFamily = 'warn';
|
|
208
|
+
let sameFamilyOrigin = 'registry';
|
|
209
|
+
let crossFamilyRereview = 'on';
|
|
210
|
+
let crossFamilyOrigin = 'registry';
|
|
211
|
+
let blockerClauses = [];
|
|
212
|
+
if (kind === 'review') {
|
|
213
|
+
const wanted = setBy(settingsView, 'review.rounds');
|
|
214
|
+
if (wanted && Number.isInteger(wanted.value)) {
|
|
215
|
+
const reason = wanted.value < chosen.rounds.min ? 'below-min' : wanted.value > registry.hardRoundCap ? 'above-cap' : null;
|
|
216
|
+
if (reason === null) {
|
|
217
|
+
rounds = wanted.value;
|
|
218
|
+
roundsOrigin = wanted.layer;
|
|
219
|
+
} else disagreements.push({ field: 'rounds', by: wanted.layer, value: wanted.value, reason });
|
|
220
|
+
}
|
|
221
|
+
const lenses = setBy(settingsView, 'review.extraLenses');
|
|
222
|
+
if (lenses && Array.isArray(lenses.value) && lenses.value.length > 0) {
|
|
223
|
+
for (const seat of seats) seat.lenses = [...(seat.lenses ?? []), ...lenses.value.filter((lens ) => !(seat.lenses ?? []).includes(lens))];
|
|
224
|
+
lensesOrigin = lenses.layer;
|
|
225
|
+
}
|
|
226
|
+
const clauses = setBy(settingsView, 'review.blockerClauses');
|
|
227
|
+
if (clauses && Array.isArray(clauses.value) && clauses.value.length > 0) {
|
|
228
|
+
blockerClauses = [...clauses.value];
|
|
229
|
+
blockersOrigin = clauses.layer;
|
|
230
|
+
}
|
|
231
|
+
const family = setBy(settingsView, 'review.sameFamily');
|
|
232
|
+
if (family && (family.value === 'refuse' || family.value === 'warn')) {
|
|
233
|
+
sameFamily = family.value;
|
|
234
|
+
sameFamilyOrigin = family.layer;
|
|
235
|
+
}
|
|
236
|
+
const rereview = setBy(settingsView, 'review.crossFamilyRereview');
|
|
237
|
+
if (rereview && (rereview.value === 'on' || rereview.value === 'off')) {
|
|
238
|
+
crossFamilyRereview = rereview.value;
|
|
239
|
+
crossFamilyOrigin = rereview.layer;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
Object.assign(protocol, {
|
|
243
|
+
seats,
|
|
244
|
+
rounds,
|
|
245
|
+
crossAnswer: chosen.crossAnswer,
|
|
246
|
+
synthesizer: chosen.synthesizer,
|
|
247
|
+
decider: chosen.decider,
|
|
248
|
+
lensesBySeat: Object.fromEntries(seats.map((seat ) => [seat.id, [...(seat.lenses ?? [])]])),
|
|
249
|
+
blockerClauses,
|
|
250
|
+
sameFamily,
|
|
251
|
+
crossFamilyRereview,
|
|
252
|
+
rereview: 'automatic',
|
|
253
|
+
invariants: registry.invariants.filter((inv ) => (inv.kinds ?? ['review']).includes(kind)).map((inv ) => inv.id),
|
|
254
|
+
origins: {
|
|
255
|
+
id: idOrigin, seats: seatsOrigin, rounds: roundsOrigin, lenses: lensesOrigin, blockerClauses: blockersOrigin,
|
|
256
|
+
sameFamily: sameFamilyOrigin, crossFamilyRereview: crossFamilyOrigin,
|
|
257
|
+
},
|
|
258
|
+
disagreements,
|
|
259
|
+
enforcement: enforcementRows(seats, agentAccess, readOnlyLimits),
|
|
260
|
+
});
|
|
261
|
+
return { ok: true, protocol };
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** `value` as JSON with object keys sorted at every depth (arrays keep their order). */
|
|
265
|
+
function canonicalJson(value ) {
|
|
266
|
+
if (Array.isArray(value)) return `[${value.map(canonicalJson).join(',')}]`;
|
|
267
|
+
if (value !== null && typeof value === 'object') {
|
|
268
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(',')}}`;
|
|
269
|
+
}
|
|
270
|
+
return JSON.stringify(value);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** 119 Q-A2 / IC-002: the sha256 hex of the resolved protocol's canonical JSON; a findings record's `protocol.digest`. */
|
|
274
|
+
function protocolDigest(protocol ) {
|
|
275
|
+
return nodeCrypto.createHash('sha256').update(canonicalJson(protocol)).digest('hex');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
/** A few compact lines for the text form of a resolved protocol (`review --action start`, `protocol`). */
|
|
279
|
+
function protocolLines(protocol ) {
|
|
280
|
+
return [
|
|
281
|
+
`protocol: id=${protocol.id} rounds=${protocol.rounds} crossAnswer=${protocol.crossAnswer} synthesizer=${protocol.synthesizer} decider=${protocol.decider} rereview=${protocol.rereview}`,
|
|
282
|
+
`protocol.seats: ${protocol.seats.map((seat ) => `${seat.id}[${(protocol.lensesBySeat[seat.id] ?? []).join(',')}]`).join(' ')}`,
|
|
283
|
+
`protocol.origins: ${Object.entries(protocol.origins).map(([field, origin]) => `${field}=${origin}`).join(' ')}`,
|
|
284
|
+
`protocol.invariants: ${protocol.invariants.join(',')}`,
|
|
285
|
+
...[...new Set ((protocol.enforcement ?? []).map((row ) => row.agent))].map((agent) => {
|
|
286
|
+
const rows = protocol.enforcement.filter((row ) => row.agent === agent);
|
|
287
|
+
const ids = (status ) => rows.filter((row ) => row.status === status).map((row ) => row.harness).join(',');
|
|
288
|
+
return `protocol.enforcement: ${agent} native=${ids('native')} unenforced=${ids('unenforced')}${ids('unknown') ? ` unknown=${ids('unknown')}` : ''}`;
|
|
289
|
+
}),
|
|
290
|
+
// A review's rule values and the project's blocker clauses, in full (C-5); a debate has none. A control
|
|
291
|
+
// character in a clause is escaped (\u00XX) so a clause cannot start a forged protocol line.
|
|
292
|
+
...(protocol.kind === 'review'
|
|
293
|
+
? [`protocol.rules: sameFamily=${protocol.sameFamily} crossFamilyRereview=${protocol.crossFamilyRereview}`,
|
|
294
|
+
...protocol.blockerClauses.map((clause ) => `protocol.blocker: ${clause.replace(/\p{Cc}/gu, (c) => `\\u${c.charCodeAt(0).toString(16).padStart(4, '0')}`)}`)]
|
|
295
|
+
: []),
|
|
296
|
+
...(protocol.disagreements?.length
|
|
297
|
+
? [`protocol.disagreements: ${protocol.disagreements.map((d ) => `field=${d.field} by=${d.by} value=${d.value} reason=${d.reason}`).join('; ')}`]
|
|
298
|
+
: []),
|
|
299
|
+
];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
module.exports = { resolveProtocol, settingsPick, atLeastAsStrict, protocolLines, protocolDigest, pathScope, gateMinSeats };
|