mandrel 2.60.0 → 2.61.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/.agents/README.md +10 -10
- package/.agents/agents/story-worker.md +1 -1
- package/.agents/docs/agentrc-reference.json +4 -82
- package/.agents/docs/configuration.md +20 -87
- package/.agents/docs/workflows.md +1 -1
- package/.agents/instructions.md +1 -3
- package/.agents/rules/gherkin-standards.md +4 -0
- package/.agents/schemas/agentrc.schema.json +11 -486
- package/.agents/schemas/story-deliver-terminal.schema.json +10 -0
- package/.agents/schemas/validation-evidence.schema.json +2 -1
- package/.agents/scripts/README.md +14 -14
- package/.agents/scripts/acceptance-eval.js +32 -164
- package/.agents/scripts/agents-bootstrap-github.js +27 -129
- package/.agents/scripts/apply-quality-bootstrap.js +4 -40
- package/.agents/scripts/audit-baselines.js +6 -27
- package/.agents/scripts/audit-labels-bootstrap.js +5 -29
- package/.agents/scripts/audit-to-stories.js +91 -361
- package/.agents/scripts/boot-sweep.js +19 -72
- package/.agents/scripts/bootstrap.js +74 -395
- package/.agents/scripts/ceremony-derive.js +9 -45
- package/.agents/scripts/check-arch-cycles.js +14 -64
- package/.agents/scripts/check-baselines.js +8 -48
- package/.agents/scripts/check-context-budget.js +46 -172
- package/.agents/scripts/check-cyclomatic.js +12 -44
- package/.agents/scripts/check-dead-exports.js +13 -64
- package/.agents/scripts/check-doc-links.js +38 -186
- package/.agents/scripts/check-gherkin-corpus.js +24 -127
- package/.agents/scripts/check-test-temp-hygiene.js +28 -169
- package/.agents/scripts/coverage-capture.js +32 -99
- package/.agents/scripts/deliver-light.js +14 -101
- package/.agents/scripts/deliver-recover.js +6 -42
- package/.agents/scripts/deliver-run.js +36 -133
- package/.agents/scripts/diagnose-friction.js +24 -116
- package/.agents/scripts/drain-pending-cleanup.js +1 -1
- package/.agents/scripts/evidence-gate.js +23 -85
- package/.agents/scripts/file-ci-gap.js +10 -50
- package/.agents/scripts/generate-config-docs.js +30 -170
- package/.agents/scripts/generate-lens-checklists.js +8 -52
- package/.agents/scripts/generate-skills-index.js +14 -112
- package/.agents/scripts/generate-workflows-doc.js +10 -70
- package/.agents/scripts/git-cleanup.js +2 -34
- package/.agents/scripts/lib/Graph.js +24 -81
- package/.agents/scripts/lib/ITicketingProvider.js +47 -143
- package/.agents/scripts/lib/Logger.js +14 -76
- package/.agents/scripts/lib/audit-baselines/engine.js +11 -31
- package/.agents/scripts/lib/audit-baselines/gate-surface.js +3 -17
- package/.agents/scripts/lib/audit-baselines/headroom.js +4 -20
- package/.agents/scripts/lib/audit-baselines/hotspots.js +3 -15
- package/.agents/scripts/lib/audit-baselines/kinds.js +23 -89
- package/.agents/scripts/lib/audit-baselines/outliers.js +6 -23
- package/.agents/scripts/lib/audit-baselines/read.js +3 -16
- package/.agents/scripts/lib/audit-baselines/staleness.js +7 -26
- package/.agents/scripts/lib/audit-baselines/surface-entry.js +7 -28
- package/.agents/scripts/lib/audit-baselines/trend.js +7 -20
- package/.agents/scripts/lib/audit-baselines/weights.js +9 -37
- package/.agents/scripts/lib/audit-suite/audit-rules-reader.js +3 -18
- package/.agents/scripts/lib/audit-suite/checklist-threading.js +26 -124
- package/.agents/scripts/lib/audit-suite/dispatch-checklist.js +14 -45
- package/.agents/scripts/lib/audit-suite/findings.js +12 -52
- package/.agents/scripts/lib/audit-suite/frontmatter.js +5 -29
- package/.agents/scripts/lib/audit-suite/index.js +1 -15
- package/.agents/scripts/lib/audit-suite/lens-checklist.js +10 -45
- package/.agents/scripts/lib/audit-suite/lens-diff-floor.js +11 -76
- package/.agents/scripts/lib/audit-suite/runner.js +13 -43
- package/.agents/scripts/lib/audit-suite/selector.js +49 -349
- package/.agents/scripts/lib/audit-suite/substitutions.js +12 -40
- package/.agents/scripts/lib/audit-suite/workflow-loader.js +3 -15
- package/.agents/scripts/lib/audit-to-stories/audit-label-taxonomy.js +11 -73
- package/.agents/scripts/lib/audit-to-stories/audit-lenses.js +8 -37
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +25 -143
- package/.agents/scripts/lib/audit-to-stories/dedupe-against-github.js +14 -80
- package/.agents/scripts/lib/audit-to-stories/epic-grouping-directive.js +4 -18
- package/.agents/scripts/lib/audit-to-stories/finding-adapter.js +7 -40
- package/.agents/scripts/lib/audit-to-stories/group-findings.js +9 -39
- package/.agents/scripts/lib/audit-to-stories/issue-corpus.js +10 -66
- package/.agents/scripts/lib/audit-to-stories/issue-index.js +6 -30
- package/.agents/scripts/lib/audit-to-stories/issues-file.js +6 -36
- package/.agents/scripts/lib/audit-to-stories/ledger-commit.js +17 -69
- package/.agents/scripts/lib/audit-to-stories/ledger-pr.js +17 -85
- package/.agents/scripts/lib/audit-to-stories/ledger-record.js +10 -48
- package/.agents/scripts/lib/audit-to-stories/parse-audit-md.js +38 -146
- package/.agents/scripts/lib/audit-to-stories/seed-from-findings.js +7 -42
- package/.agents/scripts/lib/audit-to-stories/wire-dependencies.js +10 -57
- package/.agents/scripts/lib/baseline-loader.js +12 -51
- package/.agents/scripts/lib/baseline-schema-registry.js +5 -22
- package/.agents/scripts/lib/baselines/component-matcher.js +3 -12
- package/.agents/scripts/lib/baselines/components.js +10 -61
- package/.agents/scripts/lib/baselines/coverage-updater-cli.js +7 -36
- package/.agents/scripts/lib/baselines/crap-preview-incremental.js +5 -21
- package/.agents/scripts/lib/baselines/crap-preview-scan.js +19 -45
- package/.agents/scripts/lib/baselines/crap-updater-cli.js +16 -65
- package/.agents/scripts/lib/baselines/diff-scope-cli.js +5 -33
- package/.agents/scripts/lib/baselines/duplication-scanner.js +11 -60
- package/.agents/scripts/lib/baselines/env-overrides.js +12 -67
- package/.agents/scripts/lib/baselines/envelope.js +13 -129
- package/.agents/scripts/lib/baselines/exit-codes.js +6 -49
- package/.agents/scripts/lib/baselines/git-base.js +23 -142
- package/.agents/scripts/lib/baselines/kernel.js +11 -111
- package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +9 -47
- package/.agents/scripts/lib/baselines/kinds/_crap-read.js +8 -51
- package/.agents/scripts/lib/baselines/kinds/_shared-metric.js +7 -62
- package/.agents/scripts/lib/baselines/kinds/bundle-size.js +8 -29
- package/.agents/scripts/lib/baselines/kinds/coverage.js +3 -15
- package/.agents/scripts/lib/baselines/kinds/crap.js +94 -415
- package/.agents/scripts/lib/baselines/kinds/duplication.js +4 -30
- package/.agents/scripts/lib/baselines/kinds/kind-factory.js +7 -53
- package/.agents/scripts/lib/baselines/kinds/maintainability.js +15 -80
- package/.agents/scripts/lib/baselines/kinds/mutation.js +12 -72
- package/.agents/scripts/lib/baselines/maintainability-baseline-io.js +4 -11
- package/.agents/scripts/lib/baselines/merge-envelopes.js +30 -146
- package/.agents/scripts/lib/baselines/path-canon.js +19 -128
- package/.agents/scripts/lib/baselines/preview-gates.js +8 -37
- package/.agents/scripts/lib/baselines/reader.js +14 -107
- package/.agents/scripts/lib/baselines/refresh-service.js +35 -252
- package/.agents/scripts/lib/baselines/scope.js +11 -135
- package/.agents/scripts/lib/baselines/writer.js +16 -149
- package/.agents/scripts/lib/bdd-runner-detect.js +18 -113
- package/.agents/scripts/lib/bdd-scenario-budget.js +9 -36
- package/.agents/scripts/lib/bdd-scenario-scanner.js +11 -73
- package/.agents/scripts/lib/bdd-step-index.js +26 -100
- package/.agents/scripts/lib/bootstrap/baseline-merge-driver.js +23 -103
- package/.agents/scripts/lib/bootstrap/branch-protection.js +2 -5
- package/.agents/scripts/lib/bootstrap/commit-push.js +12 -50
- package/.agents/scripts/lib/bootstrap/gh-preflight.js +14 -101
- package/.agents/scripts/lib/bootstrap/hitl-confirm.js +5 -30
- package/.agents/scripts/lib/bootstrap/install-ledger.js +17 -73
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +17 -121
- package/.agents/scripts/lib/bootstrap/manifest.js +15 -86
- package/.agents/scripts/lib/bootstrap/merge-methods.js +4 -33
- package/.agents/scripts/lib/bootstrap/preflight.js +12 -61
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +34 -235
- package/.agents/scripts/lib/bootstrap/prompt.js +21 -129
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +27 -141
- package/.agents/scripts/lib/bootstrap/summary.js +1 -8
- package/.agents/scripts/lib/bootstrap/workflow-audit.js +11 -84
- package/.agents/scripts/lib/branch-name-guard.js +4 -23
- package/.agents/scripts/lib/changed-files.js +31 -143
- package/.agents/scripts/lib/checks/core-bare-clean.js +4 -24
- package/.agents/scripts/lib/checks/index.js +18 -101
- package/.agents/scripts/lib/checks/loop-health.js +11 -53
- package/.agents/scripts/lib/checks/state.js +16 -91
- package/.agents/scripts/lib/checks/story-init-not-backgrounded.js +10 -61
- package/.agents/scripts/lib/checks/subagent-agent-tool-required.js +14 -83
- package/.agents/scripts/lib/child-exec.js +39 -108
- package/.agents/scripts/lib/cli/standard-args.js +9 -116
- package/.agents/scripts/lib/cli-args.js +31 -146
- package/.agents/scripts/lib/cli-usage.js +5 -27
- package/.agents/scripts/lib/cli-utils.js +2 -12
- package/.agents/scripts/lib/close-validation/commands.js +13 -76
- package/.agents/scripts/lib/close-validation/gates.js +92 -331
- package/.agents/scripts/lib/close-validation/process.js +121 -151
- package/.agents/scripts/lib/close-validation/projections/advisories.js +5 -31
- package/.agents/scripts/lib/close-validation/projections/crap.js +19 -67
- package/.agents/scripts/lib/close-validation/projections/head-sha.js +1 -17
- package/.agents/scripts/lib/close-validation/projections/inputs.js +4 -34
- package/.agents/scripts/lib/close-validation/projections/maintainability.js +11 -58
- package/.agents/scripts/lib/close-validation/runner.js +53 -110
- package/.agents/scripts/lib/command-header.js +6 -28
- package/.agents/scripts/lib/config/acceptance-eval.js +4 -30
- package/.agents/scripts/lib/config/baselines.js +3 -14
- package/.agents/scripts/lib/config/ci.js +8 -38
- package/.agents/scripts/lib/config/commands.js +1 -15
- package/.agents/scripts/lib/config/defaults.js +4 -33
- package/.agents/scripts/lib/config/delivery-routing.js +6 -35
- package/.agents/scripts/lib/config/explain.js +9 -80
- package/.agents/scripts/lib/config/gates/coverage.schema.js +0 -12
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +2 -30
- package/.agents/scripts/lib/config/gates/crap.schema.js +1 -34
- package/.agents/scripts/lib/config/gates/duplication.schema.js +1 -8
- package/.agents/scripts/lib/config/gates/index.js +2 -17
- package/.agents/scripts/lib/config/gates/maintainability.schema.js +1 -20
- package/.agents/scripts/lib/config/gates/mutation.schema.js +1 -7
- package/.agents/scripts/lib/config/gates/shared.js +4 -64
- package/.agents/scripts/lib/config/github.js +4 -22
- package/.agents/scripts/lib/config/limits.js +4 -57
- package/.agents/scripts/lib/config/paths.js +2 -21
- package/.agents/scripts/lib/config/qa.js +4 -38
- package/.agents/scripts/lib/config/quality.js +76 -432
- package/.agents/scripts/lib/config/runners.js +12 -56
- package/.agents/scripts/lib/config/runtime.js +13 -57
- package/.agents/scripts/lib/config/shared.js +2 -16
- package/.agents/scripts/lib/config/sync-agentrc.js +9 -50
- package/.agents/scripts/lib/config/temp-paths.js +40 -280
- package/.agents/scripts/lib/config/validate-orchestration.js +5 -17
- package/.agents/scripts/lib/config/worktree-isolation.js +9 -28
- package/.agents/scripts/lib/config-resolver.js +10 -52
- package/.agents/scripts/lib/config-schema-shared.js +1 -4
- package/.agents/scripts/lib/config-settings-schema-delivery.js +12 -294
- package/.agents/scripts/lib/config-settings-schema-quality.js +7 -219
- package/.agents/scripts/lib/config-settings-schema.js +37 -274
- package/.agents/scripts/lib/coverage-baseline.js +20 -110
- package/.agents/scripts/lib/coverage-capture-fullscope.js +12 -37
- package/.agents/scripts/lib/coverage-capture-incremental.js +12 -43
- package/.agents/scripts/lib/coverage-capture-usage.js +4 -24
- package/.agents/scripts/lib/coverage-capture.js +99 -224
- package/.agents/scripts/lib/coverage-utils.js +14 -79
- package/.agents/scripts/lib/cpu-pool.js +17 -123
- package/.agents/scripts/lib/crap-baseline-join.js +16 -88
- package/.agents/scripts/lib/crap-coordinates.js +6 -25
- package/.agents/scripts/lib/crap-engine.js +40 -153
- package/.agents/scripts/lib/crap-method-identity.js +16 -78
- package/.agents/scripts/lib/crap-utils.js +31 -155
- package/.agents/scripts/lib/cyclomatic-ceiling.js +14 -87
- package/.agents/scripts/lib/cyclomatic-scope.js +10 -50
- package/.agents/scripts/lib/dead-exports-knip.js +18 -56
- package/.agents/scripts/lib/dead-exports-mode.js +5 -24
- package/.agents/scripts/lib/degraded-mode.js +3 -26
- package/.agents/scripts/lib/dependency-parser.js +8 -40
- package/.agents/scripts/lib/dependency-version.js +13 -35
- package/.agents/scripts/lib/detect-package-manager.js +6 -36
- package/.agents/scripts/lib/doc-tiers.js +22 -126
- package/.agents/scripts/lib/duplicate-search.js +8 -72
- package/.agents/scripts/lib/env-loader.js +5 -27
- package/.agents/scripts/lib/error-redactor.js +6 -31
- package/.agents/scripts/lib/errors/index.js +2 -22
- package/.agents/scripts/lib/escomplex-ast-compat.js +22 -163
- package/.agents/scripts/lib/escomplex-kernel.js +21 -123
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +93 -419
- package/.agents/scripts/lib/feedback-loop/prior-feedback-fetcher.js +20 -98
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +27 -151
- package/.agents/scripts/lib/findings/audit-ledger.js +23 -97
- package/.agents/scripts/lib/findings/classify-finding.js +14 -69
- package/.agents/scripts/lib/findings/promote-finding.js +14 -112
- package/.agents/scripts/lib/findings/provenance-field.js +11 -52
- package/.agents/scripts/lib/findings/route-finding.js +37 -255
- package/.agents/scripts/lib/findings/semantic-issue-search.js +14 -59
- package/.agents/scripts/lib/findings/severity.js +18 -104
- package/.agents/scripts/lib/format-generated-json.js +12 -44
- package/.agents/scripts/lib/full-suite-lock.js +160 -429
- package/.agents/scripts/lib/full-suite-queue.js +213 -0
- package/.agents/scripts/lib/gates/baseline-store.js +5 -9
- package/.agents/scripts/lib/gates/friction.js +1 -3
- package/.agents/scripts/lib/generated/agentrc-validator.js +2 -2
- package/.agents/scripts/lib/gh-exec.js +31 -259
- package/.agents/scripts/lib/git/cached-fetch.js +9 -52
- package/.agents/scripts/lib/git/sync-from-base.js +15 -107
- package/.agents/scripts/lib/git-branch-cleanup.js +14 -61
- package/.agents/scripts/lib/git-branch-lifecycle.js +16 -87
- package/.agents/scripts/lib/git-utils.js +37 -161
- package/.agents/scripts/lib/github/framework-repo.js +8 -71
- package/.agents/scripts/lib/github-url.js +2 -17
- package/.agents/scripts/lib/import-graph.js +11 -38
- package/.agents/scripts/lib/install-cmd-parser.js +4 -13
- package/.agents/scripts/lib/json-utils.js +3 -18
- package/.agents/scripts/lib/label-constants.js +16 -111
- package/.agents/scripts/lib/label-taxonomy.js +4 -30
- package/.agents/scripts/lib/maintainability-engine.js +12 -80
- package/.agents/scripts/lib/maintainability-unscorable.js +5 -25
- package/.agents/scripts/lib/maintainability-utils.js +16 -92
- package/.agents/scripts/lib/mandrel-catalog.js +12 -70
- package/.agents/scripts/lib/notifications/notifier.js +13 -38
- package/.agents/scripts/lib/npm-scripts.js +4 -23
- package/.agents/scripts/lib/observability/metrics-ledger.js +16 -76
- package/.agents/scripts/lib/observability/runtime-friction.js +44 -286
- package/.agents/scripts/lib/observability/signal-validator.js +5 -37
- package/.agents/scripts/lib/observability/signals-writer.js +11 -121
- package/.agents/scripts/lib/observability/source-classifier.js +21 -203
- package/.agents/scripts/lib/observability/terse-result.js +14 -47
- package/.agents/scripts/lib/onboard/init-tail.js +13 -74
- package/.agents/scripts/lib/onboard/scaffold-docs.js +11 -34
- package/.agents/scripts/lib/orchestration/acceptance-eval-decision.js +25 -139
- package/.agents/scripts/lib/orchestration/auto-merge-cwd.js +11 -66
- package/.agents/scripts/lib/orchestration/behind-recovery.js +10 -55
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +5 -75
- package/.agents/scripts/lib/orchestration/change-set.js +7 -36
- package/.agents/scripts/lib/orchestration/check-baselines/phases/compare.js +9 -46
- package/.agents/scripts/lib/orchestration/check-baselines/phases/evaluate.js +11 -44
- package/.agents/scripts/lib/orchestration/check-baselines/phases/floors.js +5 -24
- package/.agents/scripts/lib/orchestration/check-baselines/phases/friction.js +3 -12
- package/.agents/scripts/lib/orchestration/check-baselines/phases/parse-args.js +5 -38
- package/.agents/scripts/lib/orchestration/check-baselines/phases/pipeline.js +3 -8
- package/.agents/scripts/lib/orchestration/check-baselines/phases/refresh-ack.js +28 -136
- package/.agents/scripts/lib/orchestration/check-baselines/phases/report.js +3 -13
- package/.agents/scripts/lib/orchestration/check-state.js +92 -0
- package/.agents/scripts/lib/orchestration/ci-gap-intake.js +37 -144
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +42 -189
- package/.agents/scripts/lib/orchestration/code-review.js +24 -128
- package/.agents/scripts/lib/orchestration/column-sync.js +23 -111
- package/.agents/scripts/lib/orchestration/complexity-gate.js +42 -214
- package/.agents/scripts/lib/orchestration/deliver-recover.js +36 -168
- package/.agents/scripts/lib/orchestration/dependency-analyzer.js +4 -35
- package/.agents/scripts/lib/orchestration/dependency-candidates.js +9 -41
- package/.agents/scripts/lib/orchestration/diff-magnitude.js +25 -115
- package/.agents/scripts/lib/orchestration/doc-reader.js +2 -6
- package/.agents/scripts/lib/orchestration/docs-digest.js +13 -51
- package/.agents/scripts/lib/orchestration/epic-candidates.js +13 -53
- package/.agents/scripts/lib/orchestration/epic-checklist.js +9 -33
- package/.agents/scripts/lib/orchestration/epic-container.js +41 -167
- package/.agents/scripts/lib/orchestration/epic-expansion.js +10 -40
- package/.agents/scripts/lib/orchestration/epic-rollup.js +55 -207
- package/.agents/scripts/lib/orchestration/file-assumption-enum.js +2 -22
- package/.agents/scripts/lib/orchestration/file-assumptions.js +45 -253
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-detect.js +9 -46
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches-reap.js +7 -57
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/branches.js +21 -126
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/cli.js +2 -6
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/fast-forward.js +1 -4
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/filters.js +1 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes-ff.js +9 -34
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/git-probes.js +41 -190
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/merged-tip.js +9 -45
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/parse-args.js +1 -4
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/phase-drivers.js +19 -85
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/prompts.js +3 -17
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/prune.js +1 -5
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/render.js +16 -100
- package/.agents/scripts/lib/orchestration/git-cleanup/phases/stashes.js +1 -4
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +16 -67
- package/.agents/scripts/lib/orchestration/lifecycle/emit-ledger-event.js +9 -33
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-flip-failed.js +8 -29
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +15 -68
- package/.agents/scripts/lib/orchestration/light-backstop.js +11 -49
- package/.agents/scripts/lib/orchestration/light-escalation.js +21 -89
- package/.agents/scripts/lib/orchestration/light-suitability.js +26 -231
- package/.agents/scripts/lib/orchestration/merge-block-class.js +39 -216
- package/.agents/scripts/lib/orchestration/merge-poll.js +104 -377
- package/.agents/scripts/lib/orchestration/pinned-identifier-lint.js +17 -57
- package/.agents/scripts/lib/orchestration/plan-context.js +52 -303
- package/.agents/scripts/lib/orchestration/plan-critic-conditions.js +22 -79
- package/.agents/scripts/lib/orchestration/plan-critics-evaluate.js +5 -31
- package/.agents/scripts/lib/orchestration/plan-metrics.js +29 -108
- package/.agents/scripts/lib/orchestration/plan-navigation.js +8 -27
- package/.agents/scripts/lib/orchestration/plan-persist/acceptance-handle-repair.js +12 -49
- package/.agents/scripts/lib/orchestration/plan-persist/audit-provenance.js +18 -73
- package/.agents/scripts/lib/orchestration/plan-persist/changes-repair.js +14 -78
- package/.agents/scripts/lib/orchestration/plan-persist/cross-plan-links.js +6 -30
- package/.agents/scripts/lib/orchestration/plan-persist/epic-adoption.js +14 -65
- package/.agents/scripts/lib/orchestration/plan-persist/epic-ops.js +21 -76
- package/.agents/scripts/lib/orchestration/plan-persist/external-deps.js +6 -43
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +14 -68
- package/.agents/scripts/lib/orchestration/plan-persist/plan-context-source.js +9 -41
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +49 -248
- package/.agents/scripts/lib/orchestration/plan-persist/soft-findings.js +2 -12
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +85 -368
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +8 -38
- package/.agents/scripts/lib/orchestration/plan-persist/supersede-ops.js +30 -190
- package/.agents/scripts/lib/orchestration/plan-persist/wave-collision-gate.js +9 -49
- package/.agents/scripts/lib/orchestration/plan-persist/wave-serialisation.js +7 -28
- package/.agents/scripts/lib/orchestration/plan-reachability.js +13 -42
- package/.agents/scripts/lib/orchestration/plan-run-labels/reap.js +16 -91
- package/.agents/scripts/lib/orchestration/plan-runner/worktree-sweep.js +16 -54
- package/.agents/scripts/lib/orchestration/plan-text-hygiene.js +10 -52
- package/.agents/scripts/lib/orchestration/planning/authoring-context.js +14 -109
- package/.agents/scripts/lib/orchestration/planning/memory-pool-advisory.js +11 -83
- package/.agents/scripts/lib/orchestration/pr-watch.js +48 -306
- package/.agents/scripts/lib/orchestration/project-meta-cache.js +15 -80
- package/.agents/scripts/lib/orchestration/project-meta-resolver.js +10 -51
- package/.agents/scripts/lib/orchestration/reassert-status-column.js +12 -76
- package/.agents/scripts/lib/orchestration/remote-verifier.js +12 -36
- package/.agents/scripts/lib/orchestration/resolve-stories.js +33 -164
- package/.agents/scripts/lib/orchestration/retro-proposals.js +66 -361
- package/.agents/scripts/lib/orchestration/review-base-ref.js +9 -43
- package/.agents/scripts/lib/orchestration/review-depth.js +12 -94
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +10 -111
- package/.agents/scripts/lib/orchestration/review-providers/degraded-gates.js +13 -71
- package/.agents/scripts/lib/orchestration/review-providers/findings-renderer.js +7 -51
- package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +8 -53
- package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -214
- package/.agents/scripts/lib/orchestration/review-providers/parse-findings.js +7 -52
- package/.agents/scripts/lib/orchestration/review-providers/review-depth.js +4 -33
- package/.agents/scripts/lib/orchestration/review-providers/review-provider-factory.js +11 -71
- package/.agents/scripts/lib/orchestration/review-providers/scoped-lint.js +19 -131
- package/.agents/scripts/lib/orchestration/review-providers/security-review.js +6 -89
- package/.agents/scripts/lib/orchestration/review-providers/types.js +26 -56
- package/.agents/scripts/lib/orchestration/review-providers/ultrareview.js +3 -46
- package/.agents/scripts/lib/orchestration/run-epilogue.js +40 -199
- package/.agents/scripts/lib/orchestration/run-scoped-config.js +13 -81
- package/.agents/scripts/lib/orchestration/single-story-close/close-note.js +7 -34
- package/.agents/scripts/lib/orchestration/single-story-close/failed-terminal.js +16 -89
- package/.agents/scripts/lib/orchestration/single-story-close/gate-log.js +18 -109
- package/.agents/scripts/lib/orchestration/single-story-close/phases/auto-merge.js +83 -239
- package/.agents/scripts/lib/orchestration/single-story-close/phases/base-sync.js +18 -80
- package/.agents/scripts/lib/orchestration/single-story-close/phases/close-validation.js +103 -97
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +8 -64
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +136 -486
- package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +30 -134
- package/.agents/scripts/lib/orchestration/single-story-close/phases/graphql-preflight.js +9 -50
- package/.agents/scripts/lib/orchestration/single-story-close/phases/lock-wait-pending.js +49 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +13 -86
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +20 -95
- package/.agents/scripts/lib/orchestration/single-story-close/phases/post-land.js +46 -203
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pre-gate-steps.js +8 -50
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +12 -83
- package/.agents/scripts/lib/orchestration/single-story-close/phases/push.js +6 -39
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +1 -6
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-outcome.js +4 -28
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +6 -51
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +6 -34
- package/.agents/scripts/lib/orchestration/single-story-close/phases/wrong-tree-guard.js +23 -121
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +110 -290
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +15 -69
- package/.agents/scripts/lib/orchestration/story-body-gate.js +4 -23
- package/.agents/scripts/lib/orchestration/story-close/baseline-upward-writeback.js +50 -179
- package/.agents/scripts/lib/orchestration/story-close/context-budget-writeback.js +11 -41
- package/.agents/scripts/lib/orchestration/story-close/format-autofix.js +23 -311
- package/.agents/scripts/lib/orchestration/story-close/phases/local-lens-review.js +22 -147
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +16 -67
- package/.agents/scripts/lib/orchestration/story-deliver-terminal-schema.js +12 -68
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +42 -201
- package/.agents/scripts/lib/orchestration/story-follow-ups.js +43 -245
- package/.agents/scripts/lib/orchestration/story-init-envelope.js +4 -23
- package/.agents/scripts/lib/orchestration/story-init-remote.js +2 -6
- package/.agents/scripts/lib/orchestration/story-reachability.js +3 -23
- package/.agents/scripts/lib/orchestration/task-body-validator.js +12 -126
- package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -131
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +15 -149
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +5 -33
- package/.agents/scripts/lib/orchestration/ticket-validator.js +39 -181
- package/.agents/scripts/lib/orchestration/ticketing/bulk.js +51 -244
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +39 -250
- package/.agents/scripts/lib/orchestration/ticketing/state.js +14 -68
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +46 -263
- package/.agents/scripts/lib/orchestration/ticketing.js +2 -26
- package/.agents/scripts/lib/orchestration/verify-credit.js +18 -79
- package/.agents/scripts/lib/orchestration/worktree-dirty.js +5 -30
- package/.agents/scripts/lib/path-security.js +3 -6
- package/.agents/scripts/lib/plan-phase-cleanup.js +9 -49
- package/.agents/scripts/lib/preflight-runner.js +13 -69
- package/.agents/scripts/lib/process-group.js +143 -0
- package/.agents/scripts/lib/project-root.js +2 -8
- package/.agents/scripts/lib/provider-factory.js +2 -25
- package/.agents/scripts/lib/qa/console-allowlist.js +10 -59
- package/.agents/scripts/lib/qa/qa-session.js +15 -69
- package/.agents/scripts/lib/qa/redact-evidence.js +18 -129
- package/.agents/scripts/lib/qa/resolve-qa-contract.js +26 -135
- package/.agents/scripts/lib/qa/resolve-selection.js +16 -84
- package/.agents/scripts/lib/reserved-test-ids.js +9 -47
- package/.agents/scripts/lib/runtime-deps/dep-resolution.js +13 -53
- package/.agents/scripts/lib/runtime-deps/ensure-installed.js +10 -44
- package/.agents/scripts/lib/runtime-deps/manifest.js +10 -30
- package/.agents/scripts/lib/runtime-deps/parser-major.js +15 -51
- package/.agents/scripts/lib/runtime-deps/preflight.js +4 -22
- package/.agents/scripts/lib/runtime-deps/scan-imports.js +11 -55
- package/.agents/scripts/lib/signals/detectors/common.js +12 -38
- package/.agents/scripts/lib/signals/index.js +2 -19
- package/.agents/scripts/lib/signals/schema.js +14 -109
- package/.agents/scripts/lib/signals/write.js +2 -11
- package/.agents/scripts/lib/single-story/confirm-merge.js +31 -72
- package/.agents/scripts/lib/single-story/story-merged-notify.js +8 -49
- package/.agents/scripts/lib/single-story-sweep/protection-ctx.js +4 -26
- package/.agents/scripts/lib/single-story-sweep/protection.js +13 -100
- package/.agents/scripts/lib/single-story-sweep/sweep-lock.js +60 -258
- package/.agents/scripts/lib/single-story-sweep.js +14 -97
- package/.agents/scripts/lib/skills/parse-skill.js +13 -59
- package/.agents/scripts/lib/skills/skills-index.js +8 -29
- package/.agents/scripts/lib/skills/walk-skill-files.js +17 -78
- package/.agents/scripts/lib/source-extensions.js +11 -42
- package/.agents/scripts/lib/source-text/strip-js-comments.js +8 -41
- package/.agents/scripts/lib/stdio-flush.js +9 -36
- package/.agents/scripts/lib/story-adjacency.js +8 -40
- package/.agents/scripts/lib/story-body/body-format-lints.js +22 -83
- package/.agents/scripts/lib/story-body/footer-block.js +11 -44
- package/.agents/scripts/lib/story-body/story-body.js +83 -358
- package/.agents/scripts/lib/temp-retention.js +42 -143
- package/.agents/scripts/lib/templates/decomposer-prompts.js +11 -65
- package/.agents/scripts/lib/test-env.js +12 -65
- package/.agents/scripts/lib/test-run-credit.js +10 -65
- package/.agents/scripts/lib/test-runner-contract.js +19 -74
- package/.agents/scripts/lib/test-temp.js +38 -184
- package/.agents/scripts/lib/test-tiers.js +12 -96
- package/.agents/scripts/lib/ticket-body-sections.js +21 -96
- package/.agents/scripts/lib/transpile.js +15 -74
- package/.agents/scripts/lib/util/concurrent-map.js +6 -25
- package/.agents/scripts/lib/util/parse-id-list.js +8 -34
- package/.agents/scripts/lib/util/poll-loop.js +8 -28
- package/.agents/scripts/lib/util/with-timeout.js +2 -11
- package/.agents/scripts/lib/validation-evidence.js +21 -96
- package/.agents/scripts/lib/wave-runner/footprint.js +17 -70
- package/.agents/scripts/lib/wave-runner/live-probe.js +53 -221
- package/.agents/scripts/lib/wave-runner/ready-set.js +72 -301
- package/.agents/scripts/lib/workers/crap-worker.js +11 -64
- package/.agents/scripts/lib/workers/maintainability-report-worker.js +8 -45
- package/.agents/scripts/lib/workers/maintainability-worker.js +5 -21
- package/.agents/scripts/lib/workers/serve-worker-messages.js +2 -18
- package/.agents/scripts/lib/workflow-closure.js +22 -105
- package/.agents/scripts/lib/workspace-provisioner.js +16 -54
- package/.agents/scripts/lib/worktree/git-hooks.js +15 -60
- package/.agents/scripts/lib/worktree/lifecycle/force-drain.js +20 -60
- package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +10 -62
- package/.agents/scripts/lib/worktree/lifecycle/pending-cleanup.js +22 -86
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +24 -126
- package/.agents/scripts/lib/worktree/lifecycle-manager.js +2 -20
- package/.agents/scripts/lib/worktree/node-modules-strategy.js +46 -180
- package/.agents/scripts/lib/worktree-manager.js +15 -40
- package/.agents/scripts/lint-issue-body.js +12 -68
- package/.agents/scripts/mandrel-update-preflight.js +10 -70
- package/.agents/scripts/merge-baseline.js +30 -104
- package/.agents/scripts/nav-registry-diff.js +22 -108
- package/.agents/scripts/notify.js +12 -69
- package/.agents/scripts/plan-context.js +27 -111
- package/.agents/scripts/plan-critics.js +12 -66
- package/.agents/scripts/plan-persist.js +31 -148
- package/.agents/scripts/plan-run-epilogue.js +11 -37
- package/.agents/scripts/pr-watch-with-update.js +76 -267
- package/.agents/scripts/providers/github/auth.js +3 -8
- package/.agents/scripts/providers/github/blocked-by-add.js +14 -61
- package/.agents/scripts/providers/github/board-add.js +5 -21
- package/.agents/scripts/providers/github/branch-protection.js +11 -43
- package/.agents/scripts/providers/github/cache.js +2 -14
- package/.agents/scripts/providers/github/comments.js +7 -40
- package/.agents/scripts/providers/github/compose.js +3 -19
- package/.agents/scripts/providers/github/errors.js +22 -125
- package/.agents/scripts/providers/github/issues.js +31 -123
- package/.agents/scripts/providers/github/labels.js +24 -124
- package/.agents/scripts/providers/github/mappers.js +5 -27
- package/.agents/scripts/providers/github/merge-methods.js +3 -22
- package/.agents/scripts/providers/github/project-board.js +2 -17
- package/.agents/scripts/providers/github/projects-v2-graphql.js +3 -6
- package/.agents/scripts/providers/github/request-helpers.js +5 -32
- package/.agents/scripts/providers/github/search-budget.js +9 -39
- package/.agents/scripts/providers/github/search-query.js +5 -26
- package/.agents/scripts/providers/github/sub-issue-add.js +15 -65
- package/.agents/scripts/providers/github/sub-issues.js +7 -36
- package/.agents/scripts/providers/github/tickets.js +32 -134
- package/.agents/scripts/providers/github.js +18 -59
- package/.agents/scripts/prune-plan-run-labels.js +12 -46
- package/.agents/scripts/quality-preview.js +35 -220
- package/.agents/scripts/resolve-doc-tiers.js +3 -26
- package/.agents/scripts/resolve-stories.js +16 -67
- package/.agents/scripts/resync-status-column.js +6 -25
- package/.agents/scripts/run-tests.js +29 -104
- package/.agents/scripts/single-story-close.js +23 -135
- package/.agents/scripts/single-story-confirm-merge.js +32 -139
- package/.agents/scripts/single-story-init.js +47 -209
- package/.agents/scripts/stories-wave-tick.js +102 -472
- package/.agents/scripts/sync-agentrc.js +3 -21
- package/.agents/scripts/sync-claude-agents.js +9 -55
- package/.agents/scripts/sync-claude-commands.js +20 -110
- package/.agents/scripts/test-wrapper.js +6 -43
- package/.agents/scripts/update-coverage-baseline.js +5 -22
- package/.agents/scripts/update-crap-baseline.js +7 -30
- package/.agents/scripts/update-duplication-baseline.js +16 -92
- package/.agents/scripts/update-maintainability-baseline.js +8 -62
- package/.agents/scripts/update-ticket-state.js +1 -7
- package/.agents/scripts/validate-skills.js +6 -26
- package/.agents/templates/agent-protocol.md +2 -2
- package/.agents/templates/docs/audit-sweep-runbook.md +3 -4
- package/.agents/workflows/audit-accessibility.md +4 -7
- package/.agents/workflows/audit-adrs.md +3 -6
- package/.agents/workflows/audit-architecture.md +3 -11
- package/.agents/workflows/audit-baselines.md +6 -9
- package/.agents/workflows/audit-clean-code.md +8 -12
- package/.agents/workflows/audit-data-model.md +3 -7
- package/.agents/workflows/audit-dependencies.md +4 -7
- package/.agents/workflows/audit-devops.md +4 -8
- package/.agents/workflows/audit-documentation.md +1 -4
- package/.agents/workflows/audit-mobile.md +4 -7
- package/.agents/workflows/audit-navigability.md +3 -6
- package/.agents/workflows/audit-performance.md +2 -4
- package/.agents/workflows/audit-privacy.md +4 -7
- package/.agents/workflows/audit-quality.md +4 -7
- package/.agents/workflows/audit-security.md +4 -7
- package/.agents/workflows/audit-seo.md +4 -7
- package/.agents/workflows/audit-sre.md +4 -7
- package/.agents/workflows/audit-to-stories.md +17 -30
- package/.agents/workflows/audit-ux-ui.md +4 -7
- package/.agents/workflows/helpers/audit-lens-core.md +1 -1
- package/.agents/workflows/helpers/code-quality-guardrails.md +12 -15
- package/.agents/workflows/helpers/deliver-digest.md +6 -4
- package/.agents/workflows/helpers/deliver-reference.md +114 -188
- package/.agents/workflows/helpers/deliver-story-reference.md +189 -533
- package/.agents/workflows/helpers/plan-reference.md +86 -139
- package/.agents/workflows/helpers/qa-core.md +12 -0
- package/.agents/workflows/memory-consolidate.md +1 -1
- package/.agents/workflows/qa-assist.md +27 -71
- package/.agents/workflows/qa-explore.md +19 -59
- package/.agents/workflows/qa-run.md +11 -33
- package/README.md +1 -1
- package/bin/mandrel.js +5 -46
- package/bin/postinstall.js +18 -107
- package/docs/CHANGELOG.md +25 -0
- package/lib/cli/doctor.js +11 -71
- package/lib/cli/init.js +26 -165
- package/lib/cli/migrate.js +5 -64
- package/lib/cli/registry.js +84 -467
- package/lib/cli/sync-agents.js +4 -64
- package/lib/cli/sync-commands.js +11 -64
- package/lib/cli/sync.js +34 -213
- package/lib/cli/uninstall.js +40 -219
- package/lib/cli/update.js +105 -661
- package/lib/cli/version-check.js +8 -72
- package/lib/cli/version-helpers.js +14 -87
- package/lib/migrations/helpers/retire-agentrc-key.js +11 -52
- package/lib/migrations/index.js +15 -92
- package/lib/migrations/steps/2.1.0-retire-mi-drop-knobs.js +2 -15
- package/lib/migrations/steps/2.1.0-retire-verify-concurrency-cap.js +1 -13
- package/lib/migrations/steps/2.11.0-retire-max-seed-words.js +2 -15
- package/lib/migrations/steps/2.2.0-retire-epic-ac-tags.js +9 -38
- package/lib/migrations/steps/2.20.0-retire-codebase-snapshot.js +1 -13
- package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +2 -27
- package/lib/migrations/steps/2.57.0-retire-delivery-limit-knobs.js +2 -23
- package/lib/migrations/steps/2.57.0-retire-planning-limit-knobs.js +2 -27
- package/lib/migrations/steps/2.60.0-retire-audit-results-autofile.js +2 -21
- package/lib/migrations/steps/strip-removed-agentrc-keys.js +333 -0
- package/package.json +16 -14
- package/.agents/docs/SDLC.md +0 -590
- package/.agents/docs/quality-gates.md +0 -1183
- package/.agents/rules/known-tooling-behavior.md +0 -200
- package/.agents/rules/orchestration-error-handling.md +0 -61
- package/.agents/rules/test-seams.md +0 -59
- package/.agents/schemas/baselines/lighthouse.schema.json +0 -59
- package/.agents/schemas/baselines/lint.schema.json +0 -47
- package/.agents/scripts/check-action-pinning.js +0 -260
- package/.agents/scripts/check-audit-attribution.js +0 -302
- package/.agents/scripts/check-baseline-drift.js +0 -211
- package/.agents/scripts/check-baseline-scope.js +0 -362
- package/.agents/scripts/check-generated-validator.js +0 -202
- package/.agents/scripts/check-knip-entries.js +0 -159
- package/.agents/scripts/check-lifecycle-lint.js +0 -294
- package/.agents/scripts/check-pinned-override-notes.js +0 -102
- package/.agents/scripts/check-schema-references.js +0 -368
- package/.agents/scripts/check-test-portability.js +0 -512
- package/.agents/scripts/check-workflow-citations.js +0 -218
- package/.agents/scripts/check-workflow-cli-lint.js +0 -299
- package/.agents/scripts/check-workflow-timeouts.js +0 -291
- package/.agents/scripts/install-matrix-assert.js +0 -326
- package/.agents/scripts/lib/audit-advisories.js +0 -195
- package/.agents/scripts/lib/audit-attribution.js +0 -134
- package/.agents/scripts/lib/baselines/drift-detector.js +0 -351
- package/.agents/scripts/lib/baselines/kinds/lighthouse.js +0 -87
- package/.agents/scripts/lib/baselines/kinds/lint.js +0 -184
- package/.agents/scripts/lib/baselines/orphan-pruner.js +0 -233
- package/.agents/scripts/lib/baselines/scope-assert.js +0 -223
- package/.agents/scripts/lib/baselines/scope-inventory.js +0 -314
- package/.agents/scripts/lib/c8-cli-path.js +0 -21
- package/.agents/scripts/lib/config/gates/lighthouse.schema.js +0 -51
- package/.agents/scripts/lib/config/gates/lint.schema.js +0 -18
- package/.agents/scripts/lib/dynamic-workflow/architecture-report-contract.js +0 -70
- package/.agents/scripts/lib/dynamic-workflow/audit-orchestrator.js +0 -284
- package/.agents/scripts/lib/dynamic-workflow/clean-code-report-contract.js +0 -80
- package/.agents/scripts/lib/dynamic-workflow/degraded-coverage.js +0 -81
- package/.agents/scripts/lib/dynamic-workflow/documentation-report-contract.js +0 -87
- package/.agents/scripts/lib/dynamic-workflow/performance-report-contract.js +0 -74
- package/.agents/scripts/lib/dynamic-workflow/quality-report-contract.js +0 -90
- package/.agents/scripts/lib/dynamic-workflow/report-contract-core.js +0 -43
- package/.agents/scripts/lib/dynamic-workflow/security-report-contract.js +0 -83
- package/.agents/scripts/lib/fs-walk.js +0 -52
- package/.agents/scripts/lib/knip-config-resolver.js +0 -181
- package/.agents/scripts/lib/knip-entry-sync.js +0 -452
- package/.agents/scripts/lib/pinned-override-notes.js +0 -88
- package/.agents/scripts/lib/pinned-override-resolve.js +0 -212
- package/.agents/scripts/lib/test-isolate/cli-options.js +0 -93
- package/.agents/scripts/lib/test-isolate/env-snapshot-loader.js +0 -52
- package/.agents/scripts/lib/test-isolate/list-files.js +0 -90
- package/.agents/scripts/lib/test-isolate/parse-tap.js +0 -75
- package/.agents/scripts/lib/test-isolate/progress-log.js +0 -45
- package/.agents/scripts/lib/test-isolate/render-report.js +0 -97
- package/.agents/scripts/lib/test-isolate/run-isolate.js +0 -87
- package/.agents/scripts/lib/test-isolate/runner.js +0 -483
- package/.agents/scripts/lib/test-profile/parse-tap.js +0 -136
- package/.agents/scripts/lib/test-profile/render-report.js +0 -45
- package/.agents/scripts/lint-label-vocabulary.js +0 -214
- package/.agents/scripts/post-structured-comment.js +0 -127
- package/.agents/scripts/provision-git-hooks.js +0 -85
- package/.agents/scripts/prune-baseline-orphans.js +0 -181
- package/.agents/scripts/run-coverage.js +0 -197
- package/.agents/scripts/run-lint.js +0 -133
- package/.agents/scripts/run-test-profile.js +0 -129
- package/.agents/scripts/run-verify.js +0 -125
- package/.agents/scripts/test-isolate.js +0 -55
- package/.agents/scripts/update-dead-exports-baseline.js +0 -321
|
@@ -1,55 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* graduator
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* `spawn`-based child runner, the `git cat-file` path probe, the
|
|
7
|
-
* `gh search issues` idempotency probe, the `gh issue create` filer, the
|
|
8
|
-
* `isAutoFileEnabled` toggle reader, and the route → probe → file
|
|
9
|
-
* envelope walk. This module folds all of that into one place so a
|
|
10
|
-
* graduator becomes a thin shell that injects the bits that genuinely
|
|
11
|
-
* differ (the body/title/label builders).
|
|
12
|
-
*
|
|
13
|
-
* Story #5003 removed the structured-comment read limb. Both comment-reading
|
|
14
|
-
* graduators were Epic-era — they walked an Epic's `verification-results`
|
|
15
|
-
* comment, and v2 has no Epics — leaving `retro-proposals-graduator.js` and
|
|
16
|
-
* its pre-parsed `findings[]` as the one live caller.
|
|
17
|
-
*
|
|
18
|
-
* The third `runGh` spawn copy in `prior-feedback-fetcher.js` is also
|
|
19
|
-
* collapsed onto the single `runChild` helper here.
|
|
20
|
-
*
|
|
21
|
-
* Story #4415 / Epic #4406 hardens the walk so it is bounded and
|
|
22
|
-
* replay-safe — the shared mechanism the retro auto-filer will reuse:
|
|
23
|
-
*
|
|
24
|
-
* - **Content-hash idempotency markers.** Follow-up markers derive from
|
|
25
|
-
* a `category|path|title` digest (`contentFingerprint`) instead of a
|
|
26
|
-
* `(epicId, parse-index)` ordinal, so a finding keeps its marker when
|
|
27
|
-
* sibling findings are added, removed, or reordered in the source
|
|
28
|
-
* comment, and two distinct findings never collide.
|
|
29
|
-
* - **Legacy-marker recognition.** The idempotency probe also checks the
|
|
30
|
-
* legacy `(epicId, parse-index)` marker so findings filed before the
|
|
31
|
-
* fingerprint cutover are not re-filed.
|
|
32
|
-
* - **Bounded spawns.** `runChild` enforces a caller-overridable timeout
|
|
33
|
-
* (default 30000 ms) and kills a child that overruns instead of
|
|
34
|
-
* hanging finalize forever.
|
|
35
|
-
* - **Probe-error vs confirmed-missing.** A `git cat-file` spawn failure
|
|
36
|
-
* (or timeout) records the finding as skipped `probe-error`, not the
|
|
37
|
-
* confirmed-missing `file-removed`.
|
|
38
|
-
* - **Per-run filing cap.** `graduate()` stops filing once
|
|
39
|
-
* `maxFilingsPerRun` issues are created and records the excess as
|
|
40
|
-
* skipped `cap-reached`.
|
|
41
|
-
* - **Pre-parsed / path-less seam.** `graduate()` takes its findings as a
|
|
42
|
-
* pre-parsed array, and a path-less finding skips the path-exists gate
|
|
43
|
-
* instead of being misclassified `file-removed` — the seam the retro
|
|
44
|
-
* auto-filer consumes.
|
|
45
|
-
* - **Durable cross-repo deferral.** Cross-repo-deferred findings are
|
|
46
|
-
* upserted into a structured comment on the Epic instead of only a
|
|
47
|
-
* log line.
|
|
48
|
-
* - **Routed, never re-pointed.** Ownership routing is delegated to
|
|
49
|
-
* `github/framework-repo.js#routeOwnership`; an unroutable bucket is
|
|
50
|
-
* skipped `unroutable` and named in that same durable comment. The
|
|
51
|
-
* predecessor resolved an absent framework slug to the consumer's own
|
|
52
|
-
* repo, which silently mis-filed framework-owned work.
|
|
2
|
+
* Shared graduator walk: route → path probe → idempotency probe → cap → file.
|
|
3
|
+
* A graduator injects only its title/body/label/marker builders (`spec`).
|
|
4
|
+
* The walk is bounded (spawn timeouts, per-run filing cap) and replay-safe
|
|
5
|
+
* (content-hash markers survive sibling reordering).
|
|
53
6
|
*/
|
|
54
7
|
|
|
55
8
|
import { spawn as defaultSpawn } from 'node:child_process';
|
|
@@ -61,71 +14,25 @@ import { LABEL_COLORS } from '../label-constants.js';
|
|
|
61
14
|
import { classifyPathSource as defaultClassifier } from '../observability/source-classifier.js';
|
|
62
15
|
import { upsertStructuredComment } from '../orchestration/ticketing.js';
|
|
63
16
|
|
|
64
|
-
/**
|
|
65
|
-
* Default child-process timeout. A hung `gh`/`git` spawn previously blocked
|
|
66
|
-
* finalize indefinitely; the walk now caps every spawn at this bound unless
|
|
67
|
-
* a caller overrides it.
|
|
68
|
-
*/
|
|
69
17
|
const DEFAULT_RUN_CHILD_TIMEOUT_MS = 30000;
|
|
70
18
|
|
|
71
|
-
/**
|
|
72
|
-
* Default per-run filing cap. `graduate()` files at most this many follow-up
|
|
73
|
-
* issues per invocation; the remainder is recorded as skipped `cap-reached`.
|
|
74
|
-
*/
|
|
75
19
|
export const DEFAULT_MAX_FILINGS_PER_RUN = 20;
|
|
76
20
|
|
|
77
|
-
/**
|
|
78
|
-
* Structured-comment type used to durably persist cross-repo-deferred
|
|
79
|
-
* findings on the Epic. Registered in `STRUCTURED_COMMENT_TYPES`.
|
|
80
|
-
*/
|
|
21
|
+
/** Registered in `STRUCTURED_COMMENT_TYPES`. */
|
|
81
22
|
const CROSS_REPO_DEFERRED_COMMENT_TYPE = 'cross-repo-deferred';
|
|
82
23
|
|
|
83
|
-
/**
|
|
84
|
-
* Explicit, greppable opt-back-in to live issue filing from a context the
|
|
85
|
-
* guard below refuses (Story #4837). Deliberately shaped like
|
|
86
|
-
* `MANDREL_TEST_ALLOW_REAL_TEMP` (`config/temp-paths.js`) rather than a new
|
|
87
|
-
* bespoke flag: same env-var idiom, same "an escape hatch must be visible in
|
|
88
|
-
* a grep" posture.
|
|
89
|
-
*/
|
|
24
|
+
/** Explicit, greppable opt-in to live filing from a context the guard refuses. */
|
|
90
25
|
const ALLOW_LIVE_FILING_ENV = 'MANDREL_ALLOW_LIVE_ISSUE_FILING';
|
|
91
26
|
|
|
92
|
-
/**
|
|
93
|
-
* Skip reason recorded for every finding a refused filing context drops.
|
|
94
|
-
* Module-local: it reaches callers as data on the returned envelope, so
|
|
95
|
-
* exporting the constant would only add a symbol nothing imports.
|
|
96
|
-
*/
|
|
97
27
|
const LIVE_FILING_BLOCKED_REASON = 'live-api-guard';
|
|
98
28
|
|
|
99
|
-
/** `NODE_ENV` values that declare this process is not a production run. */
|
|
100
29
|
const NON_PRODUCTION_NODE_ENVS = new Set(['test', 'development']);
|
|
101
30
|
|
|
102
31
|
/**
|
|
103
|
-
* Decide whether
|
|
104
|
-
*
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* `dsj1984/mandrel` tracker — from fixture findings anchored to `epic-101`
|
|
108
|
-
* and `epic-777` — by a development run of the filing path. Nothing in the
|
|
109
|
-
* walk distinguished "a real close is filing a real follow-up" from "someone
|
|
110
|
-
* is exercising this module", so the only thing standing between a test and
|
|
111
|
-
* the production tracker was the author remembering to stub `spawnImpl`.
|
|
112
|
-
*
|
|
113
|
-
* **The seam.** There are exactly two ways to be safe, and this returns
|
|
114
|
-
* `allowed` only for them:
|
|
115
|
-
*
|
|
116
|
-
* 1. `spawnImpl` was injected — the walk then spawns the caller's stub and
|
|
117
|
-
* no child process reaches `gh` at all. This is the seam
|
|
118
|
-
* `.agents/rules/test-seams.md` already mandates, so a well-behaved test
|
|
119
|
-
* is unaffected.
|
|
120
|
-
* 2. The process provably is **not** a test or development context — not a
|
|
121
|
-
* node:test run (per the single shared detector in
|
|
122
|
-
* `config/temp-paths.js#inNodeTestContext`) and not a run that declared
|
|
123
|
-
* itself non-production via `NODE_ENV`.
|
|
124
|
-
*
|
|
125
|
-
* **Fail closed.** Anything else refuses: a test context with the real
|
|
126
|
-
* `spawn` (the #4833/#4834 shape), and — critically — a context that cannot
|
|
127
|
-
* be *decided*, because an unreadable env is not evidence of production. The
|
|
128
|
-
* refusal is a skip, not a throw: observability must never fail a close.
|
|
32
|
+
* Decide whether the walk may reach the live GitHub API. Allowed only when
|
|
33
|
+
* `spawnImpl` is injected (no child reaches `gh`) or the process is provably
|
|
34
|
+
* not a test/development run. Fails closed — an undecidable env refuses — and
|
|
35
|
+
* refusal is a skip, never a throw: observability must not fail a close.
|
|
129
36
|
*
|
|
130
37
|
* @param {object} opts
|
|
131
38
|
* @param {Function} [opts.spawnImpl]
|
|
@@ -141,38 +48,26 @@ function resolveFilingContext({
|
|
|
141
48
|
const refuse = { allowed: false, reason: LIVE_FILING_BLOCKED_REASON };
|
|
142
49
|
const allow = { allowed: true, reason: null };
|
|
143
50
|
|
|
144
|
-
// An injected seam cannot reach the live API by construction.
|
|
145
51
|
if (typeof spawnImpl === 'function') return allow;
|
|
146
52
|
|
|
147
|
-
// Undecidable context → refuse. Both inputs must be readable for the
|
|
148
|
-
// detector's answer to mean anything.
|
|
149
53
|
if (env === null || typeof env !== 'object' || !Array.isArray(execArgv)) {
|
|
150
54
|
return refuse;
|
|
151
55
|
}
|
|
152
56
|
try {
|
|
153
57
|
if (env[ALLOW_LIVE_FILING_ENV] === '1') return allow;
|
|
154
58
|
if (inNodeTestContext(env, execArgv)) return refuse;
|
|
155
|
-
//
|
|
156
|
-
// development context". `lib/test-env.js` stamps `NODE_ENV=test` on the
|
|
157
|
-
// whole suite environment, and `development` is the universal marker for
|
|
158
|
-
// a hand-run session; nothing on the close path sets either.
|
|
59
|
+
// The suite stamps NODE_ENV=test; the close path sets neither value.
|
|
159
60
|
return NON_PRODUCTION_NODE_ENVS.has(String(env.NODE_ENV ?? ''))
|
|
160
61
|
? refuse
|
|
161
62
|
: allow;
|
|
162
63
|
} catch {
|
|
163
|
-
// An env we cannot even read is not evidence of production.
|
|
164
64
|
return refuse;
|
|
165
65
|
}
|
|
166
66
|
}
|
|
167
67
|
|
|
168
68
|
/**
|
|
169
|
-
*
|
|
170
|
-
*
|
|
171
|
-
* finding content, never on its position in the source comment, so the
|
|
172
|
-
* marker survives sibling insert/remove/reorder churn. Distinct triples
|
|
173
|
-
* yield distinct digests (SHA-256, truncated to 16 hex chars for a compact
|
|
174
|
-
* marker that still has a negligible collision probability across a single
|
|
175
|
-
* Epic's finding set).
|
|
69
|
+
* Position-independent `category|path|title` digest, so a marker survives
|
|
70
|
+
* sibling reordering (SHA-256 truncated to 16 hex).
|
|
176
71
|
*
|
|
177
72
|
* @param {{ category?: unknown, path?: unknown, title?: unknown }} parts
|
|
178
73
|
* @returns {string} 16-char lowercase hex digest.
|
|
@@ -184,29 +79,16 @@ export function contentFingerprint({ category, path, title } = {}) {
|
|
|
184
79
|
}
|
|
185
80
|
|
|
186
81
|
/**
|
|
187
|
-
*
|
|
188
|
-
* `
|
|
189
|
-
*
|
|
190
|
-
* `timedOut: true` with a matching `spawnError`.
|
|
191
|
-
*
|
|
192
|
-
* This is the single spawn helper for the feedback-loop modules. Both
|
|
193
|
-
* graduators and `prior-feedback-fetcher.js` route their child-process
|
|
194
|
-
* reads through it so the error envelope stays consistent. `stdio` is
|
|
195
|
-
* always `['ignore', 'pipe', 'pipe']`; callers that need extra spawn
|
|
196
|
-
* options (e.g. omitting `cwd`) pass `undefined` and the option is
|
|
197
|
-
* dropped by the child_process layer.
|
|
198
|
-
*
|
|
199
|
-
* A caller-overridable `timeoutMs` (default {@link DEFAULT_RUN_CHILD_TIMEOUT_MS})
|
|
200
|
-
* bounds the wait: when it elapses the child is SIGKILL'd and the promise
|
|
201
|
-
* resolves with `{ code: null, timedOut: true, spawnError }` rather than
|
|
202
|
-
* hanging. Pass `0`/`Infinity` to disable the watchdog.
|
|
82
|
+
* The feedback loop's single spawn helper. Never throws: spawn errors land in
|
|
83
|
+
* `spawnError`; an overrun is SIGKILL'd and resolves `timedOut: true`.
|
|
84
|
+
* `timeoutMs` of `0`/`Infinity` disables the watchdog.
|
|
203
85
|
*
|
|
204
86
|
* @param {object} opts
|
|
205
|
-
* @param {string} opts.cmd
|
|
206
|
-
* @param {string[]} opts.args
|
|
207
|
-
* @param {Function} [opts.spawnImpl]
|
|
208
|
-
* @param {string} [opts.cwd]
|
|
209
|
-
* @param {number} [opts.timeoutMs]
|
|
87
|
+
* @param {string} opts.cmd
|
|
88
|
+
* @param {string[]} opts.args
|
|
89
|
+
* @param {Function} [opts.spawnImpl]
|
|
90
|
+
* @param {string} [opts.cwd]
|
|
91
|
+
* @param {number} [opts.timeoutMs]
|
|
210
92
|
* @returns {Promise<{ code: number|null, stdout: string, stderr: string, spawnError: Error|null, timedOut: boolean }>}
|
|
211
93
|
*/
|
|
212
94
|
export function runChild({
|
|
@@ -249,7 +131,7 @@ export function runChild({
|
|
|
249
131
|
try {
|
|
250
132
|
child.kill?.('SIGKILL');
|
|
251
133
|
} catch {
|
|
252
|
-
//
|
|
134
|
+
// already dead / stub child
|
|
253
135
|
}
|
|
254
136
|
finish({
|
|
255
137
|
code: null,
|
|
@@ -264,14 +146,9 @@ export function runChild({
|
|
|
264
146
|
timedOut: true,
|
|
265
147
|
});
|
|
266
148
|
}, timeoutMs);
|
|
267
|
-
//
|
|
268
|
-
// the
|
|
269
|
-
//
|
|
270
|
-
// child whose handles close early — or a stub in tests — leaves the
|
|
271
|
-
// loop idle; an unref'd timer would then never fire, so the timeout
|
|
272
|
-
// silently would not bound a hung spawn (and the awaiting promise
|
|
273
|
-
// would hang forever). `finish()` always clearTimeout()s it, so the
|
|
274
|
-
// ref'd timer never outlives its purpose.
|
|
149
|
+
// Deliberately NOT unref'd: a child whose handles close early (or a
|
|
150
|
+
// stub) leaves the loop idle, and an unref'd watchdog would never fire.
|
|
151
|
+
// `finish()` always clears it.
|
|
275
152
|
}
|
|
276
153
|
child.stdout?.on('data', (chunk) => {
|
|
277
154
|
stdout += chunk.toString();
|
|
@@ -289,15 +166,10 @@ export function runChild({
|
|
|
289
166
|
}
|
|
290
167
|
|
|
291
168
|
/**
|
|
292
|
-
*
|
|
293
|
-
*
|
|
294
|
-
* #5341: the toggle defaults to `false` and only an explicit `true` enables
|
|
295
|
-
* it, because the filings the channel produced unattended were dominated by
|
|
296
|
-
* noise (see `config-settings-schema-delivery.js` for the measured record).
|
|
169
|
+
* Opt-in `delivery.feedbackLoop.<key>` reader: only an explicit `true`
|
|
170
|
+
* enables filing, because unattended filings were dominated by noise.
|
|
297
171
|
*
|
|
298
|
-
* @param {string} toggleKey
|
|
299
|
-
* (today, only "retroProposals" — the factory stays keyed so the next
|
|
300
|
-
* graduator does not have to reinvent the resolution)
|
|
172
|
+
* @param {string} toggleKey
|
|
301
173
|
* @returns {(config: object|undefined|null) => boolean}
|
|
302
174
|
*/
|
|
303
175
|
export function makeIsAutoFileEnabled(toggleKey) {
|
|
@@ -307,13 +179,8 @@ export function makeIsAutoFileEnabled(toggleKey) {
|
|
|
307
179
|
}
|
|
308
180
|
|
|
309
181
|
/**
|
|
310
|
-
*
|
|
311
|
-
*
|
|
312
|
-
* Resolves `{ exists, probeError }`:
|
|
313
|
-
*
|
|
314
|
-
* - `git cat-file -e <ref>:<path>` exit 0 → `{ exists: true, probeError: false }`
|
|
315
|
-
* - clean non-zero exit (file genuinely absent) → `{ exists: false, probeError: false }`
|
|
316
|
-
* - spawn failure / timeout (cannot decide) → `{ exists: false, probeError: true }`
|
|
182
|
+
* `git cat-file -e <ref>:<path>`; a spawn failure/timeout is `probeError`,
|
|
183
|
+
* distinct from a confirmed-missing file.
|
|
317
184
|
*
|
|
318
185
|
* @param {object} opts
|
|
319
186
|
* @param {string} opts.ref
|
|
@@ -344,16 +211,8 @@ export async function probePathStatus({
|
|
|
344
211
|
}
|
|
345
212
|
|
|
346
213
|
/**
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
* without leaking into the visible body, but the `<` / `>` delimiters are
|
|
350
|
-
* NOT index-safe as a query: GitHub full-text search DOES index the text
|
|
351
|
-
* inside an HTML comment, yet a query that carries the `<!--` / `-->`
|
|
352
|
-
* delimiters never matches that indexed text (measured against this repo,
|
|
353
|
-
* Story #4657). Stripping the delimiters and trimming yields the bare marker
|
|
354
|
-
* text — `retro-proposal-followup: <fp>` — which the index matches.
|
|
355
|
-
* The caller-facing marker is left untouched; normalization is the probe's
|
|
356
|
-
* own concern.
|
|
214
|
+
* GitHub search indexes the text inside an HTML-comment marker, but a query
|
|
215
|
+
* carrying the `<!--`/`-->` delimiters never matches it; strip them.
|
|
357
216
|
*
|
|
358
217
|
* @param {string} marker
|
|
359
218
|
* @returns {string}
|
|
@@ -364,11 +223,8 @@ function normalizeMarkerQuery(marker) {
|
|
|
364
223
|
}
|
|
365
224
|
|
|
366
225
|
/**
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
* the empty string — deliberately NOT to `'open'`: an unknown state must
|
|
370
|
-
* never authorize editing somebody's issue (see
|
|
371
|
-
* {@link resolveFollowUpRecurrence}).
|
|
226
|
+
* `state` defaults to `''`, never `'open'`: an unknown state must not
|
|
227
|
+
* authorize editing an issue.
|
|
372
228
|
*
|
|
373
229
|
* @param {object} row
|
|
374
230
|
* @returns {{ number: number|null, state: string, url: string }}
|
|
@@ -383,15 +239,8 @@ function toFollowUpRef(row) {
|
|
|
383
239
|
}
|
|
384
240
|
|
|
385
241
|
/**
|
|
386
|
-
*
|
|
387
|
-
*
|
|
388
|
-
* so we hit the body field directly, querying the delimiter-stripped marker
|
|
389
|
-
* text (see {@link normalizeMarkerQuery}) — the raw `<!-- … -->` form never
|
|
390
|
-
* matches the index.
|
|
391
|
-
*
|
|
392
|
-
* Returns `null` when nothing matched OR when the probe could not decide
|
|
393
|
-
* (spawn/parse error): the deliberate degrade-toward-filing posture, better
|
|
394
|
-
* to risk a duplicate than swallow the finding entirely.
|
|
242
|
+
* `null` on no match OR an undecidable probe — degrade toward filing: a
|
|
243
|
+
* duplicate beats a swallowed finding.
|
|
395
244
|
*
|
|
396
245
|
* @returns {Promise<{ number: number|null, state: string, url: string }|null>}
|
|
397
246
|
*/
|
|
@@ -428,46 +277,23 @@ async function searchFollowUpByMarker({
|
|
|
428
277
|
}
|
|
429
278
|
}
|
|
430
279
|
|
|
431
|
-
/**
|
|
432
|
-
* Probe whether a follow-up issue carrying the given idempotency marker
|
|
433
|
-
* already exists in the routed repo. Thin boolean façade over
|
|
434
|
-
* {@link searchFollowUpByMarker} — kept as the module's exported probe seam
|
|
435
|
-
* so callers that only need the yes/no do not have to know about the issue
|
|
436
|
-
* identity the recurrence path resolves.
|
|
437
|
-
*
|
|
438
|
-
* @returns {Promise<boolean>}
|
|
439
|
-
*/
|
|
280
|
+
/** @returns {Promise<boolean>} */
|
|
440
281
|
export async function probeMarkerExists(opts) {
|
|
441
282
|
return (await searchFollowUpByMarker(opts)) !== null;
|
|
442
283
|
}
|
|
443
284
|
|
|
444
285
|
/**
|
|
445
|
-
* Strongly-consistent
|
|
446
|
-
*
|
|
447
|
-
*
|
|
448
|
-
*
|
|
449
|
-
*
|
|
450
|
-
* label-scoped `gh issue list … --state all` is strongly consistent, so it
|
|
451
|
-
* closes that window. The list is narrowed by the follow-up's own labels
|
|
452
|
-
* (supplied by the same `spec.buildFollowUp` that writes the marker, so the
|
|
453
|
-
* two agree by construction) to keep the read bounded.
|
|
454
|
-
*
|
|
455
|
-
* `markers` is a LIST of body substrings, any one of which identifies a prior
|
|
456
|
-
* filing (Story #4837). One finding can have been filed under more than one
|
|
457
|
-
* marker shape — the retro graduator's pre-cutover marker embedded the run
|
|
458
|
-
* anchor, so the same finding sits behind `epic-<anchor>-<fp>` on already-
|
|
459
|
-
* filed issues and behind the anchor-free `<fp>` on new ones. Matching any of
|
|
460
|
-
* them is what stops a marker-format change from re-filing the whole backlog.
|
|
461
|
-
*
|
|
462
|
-
* Returns `null` when nothing matched, or on any spawn/parse error — the
|
|
463
|
-
* deliberate degrade-toward-filing posture: an undecidable probe risks a
|
|
464
|
-
* duplicate rather than swallowing the finding.
|
|
286
|
+
* Strongly-consistent last gate before creating: the search index can lag
|
|
287
|
+
* long enough to miss a duplicate filed seconds earlier, while a
|
|
288
|
+
* label-scoped `gh issue list --state all` cannot. Any of `markers` matching
|
|
289
|
+
* counts, so a marker-format change does not re-file the backlog. `null` on
|
|
290
|
+
* no match or error (degrade toward filing).
|
|
465
291
|
*
|
|
466
292
|
* @param {object} opts
|
|
467
|
-
* @param {string[]} opts.markers
|
|
293
|
+
* @param {string[]} opts.markers
|
|
468
294
|
* @param {string} opts.owner
|
|
469
295
|
* @param {string} opts.repo
|
|
470
|
-
* @param {string[]} [opts.labels]
|
|
296
|
+
* @param {string[]} [opts.labels]
|
|
471
297
|
* @param {string} [opts.ghPath]
|
|
472
298
|
* @param {Function} [opts.spawnImpl]
|
|
473
299
|
* @param {string} [opts.cwd]
|
|
@@ -518,9 +344,7 @@ async function findExistingFollowUp({
|
|
|
518
344
|
tokens.some((token) => issue.body.includes(token)),
|
|
519
345
|
);
|
|
520
346
|
if (matches.length === 0) return null;
|
|
521
|
-
// Prefer an
|
|
522
|
-
// one is a decided follow-up. When several match, the open one is the one a
|
|
523
|
-
// human is still looking at.
|
|
347
|
+
// Prefer an open match: a closed one is a decided follow-up.
|
|
524
348
|
const open = matches.find(
|
|
525
349
|
(issue) => String(issue?.state ?? '').toLowerCase() === 'open',
|
|
526
350
|
);
|
|
@@ -528,13 +352,8 @@ async function findExistingFollowUp({
|
|
|
528
352
|
}
|
|
529
353
|
|
|
530
354
|
/**
|
|
531
|
-
*
|
|
532
|
-
*
|
|
533
|
-
* to keep one issue current, not to mint issue #N+1 whose only new
|
|
534
|
-
* information is that the count went up.
|
|
535
|
-
*
|
|
536
|
-
* Body-only: labels, title, assignees and state are left exactly as a human
|
|
537
|
-
* may have curated them.
|
|
355
|
+
* Recurrence path: refresh the body only, leaving human-curated labels,
|
|
356
|
+
* title, assignees and state untouched.
|
|
538
357
|
*
|
|
539
358
|
* @returns {Promise<{ url: string|null, error: string|null }>}
|
|
540
359
|
*/
|
|
@@ -574,14 +393,10 @@ export async function updateFollowUpIssue({
|
|
|
574
393
|
return { url: (res.stdout || '').trim(), error: null };
|
|
575
394
|
}
|
|
576
395
|
|
|
577
|
-
/** Prefix of the per-category friction axis the feedback loop mints. */
|
|
578
396
|
const FRICTION_LABEL_PREFIX = 'friction::';
|
|
579
397
|
|
|
580
398
|
/**
|
|
581
|
-
*
|
|
582
|
-
* mint. Only two axes reach this path — `meta::*` (routing) and
|
|
583
|
-
* `friction::<category>` (the telemetry bucket) — so the mapping is a
|
|
584
|
-
* two-branch lookup rather than a registry.
|
|
399
|
+
* Only `meta::*` and `friction::<category>` labels reach this path.
|
|
585
400
|
*
|
|
586
401
|
* @param {string} name
|
|
587
402
|
* @returns {{ color: string, description: string }}
|
|
@@ -600,11 +415,7 @@ function describeMintedLabel(name) {
|
|
|
600
415
|
}
|
|
601
416
|
|
|
602
417
|
/**
|
|
603
|
-
*
|
|
604
|
-
* `labelCache`. Returns `null` when the set could not be established —
|
|
605
|
-
* "verification unavailable", which is deliberately NOT the same as "the repo
|
|
606
|
-
* has no labels": an unreadable set must not be read as proof that every
|
|
607
|
-
* label is missing.
|
|
418
|
+
* Memoized per repo. `known: null` means unverifiable, not "no labels".
|
|
608
419
|
*
|
|
609
420
|
* @returns {Promise<{ known: Set<string>|null, error: string|null }>}
|
|
610
421
|
*/
|
|
@@ -654,28 +465,16 @@ async function readLiveLabelNames({
|
|
|
654
465
|
}
|
|
655
466
|
|
|
656
467
|
/**
|
|
657
|
-
* Mint
|
|
658
|
-
*
|
|
659
|
-
*
|
|
660
|
-
*
|
|
661
|
-
* the repo before it creates anything, and fails the whole call when one is
|
|
662
|
-
* absent. The feedback loop mints two axes that no bootstrap can enumerate
|
|
663
|
-
* ahead of time — `meta::consumer-improvement` is absent from `LABEL_TAXONOMY`
|
|
664
|
-
* outright, and `friction::<category>` names come from live telemetry — so on
|
|
665
|
-
* a repo that never had them, *every* filing failed. The failure landed in the
|
|
666
|
-
* graduator's `errors[]`, which the run epilogue did not surface, so a
|
|
667
|
-
* hard-failing feedback loop rendered as `filed: 0`: indistinguishable from
|
|
668
|
-
* "nothing was actionable".
|
|
669
|
-
*
|
|
670
|
-
* Degrades rather than blocks: when the live set cannot be read, this returns
|
|
671
|
-
* no `missing` entries so the caller still attempts the filing (the old
|
|
672
|
-
* behaviour) instead of refusing on an unproven premise.
|
|
468
|
+
* Mint absent labels: `gh issue create` fails the whole call on any unknown
|
|
469
|
+
* `--label`, and `friction::<category>` names come from live telemetry so no
|
|
470
|
+
* bootstrap can pre-create them. An unreadable live set reports nothing
|
|
471
|
+
* `missing`, so the caller still attempts the filing.
|
|
673
472
|
*
|
|
674
473
|
* @param {object} opts
|
|
675
474
|
* @param {string} opts.owner
|
|
676
475
|
* @param {string} opts.repo
|
|
677
476
|
* @param {string[]} opts.labels
|
|
678
|
-
* @param {Map<string, Set<string>>} [opts.labelCache]
|
|
477
|
+
* @param {Map<string, Set<string>>} [opts.labelCache]
|
|
679
478
|
* @param {string} [opts.ghPath]
|
|
680
479
|
* @param {Function} [opts.spawnImpl]
|
|
681
480
|
* @param {string} [opts.cwd]
|
|
@@ -706,7 +505,6 @@ export async function ensureIssueLabels({
|
|
|
706
505
|
cwd,
|
|
707
506
|
timeoutMs,
|
|
708
507
|
});
|
|
709
|
-
// Verification unavailable — attempt the filing anyway rather than refuse.
|
|
710
508
|
if (!known) return { created: [], missing: [], errors: error ? [error] : [] };
|
|
711
509
|
|
|
712
510
|
const created = [];
|
|
@@ -735,8 +533,7 @@ export async function ensureIssueLabels({
|
|
|
735
533
|
const failed =
|
|
736
534
|
Boolean(res.spawnError) ||
|
|
737
535
|
(typeof res.code === 'number' && res.code !== 0);
|
|
738
|
-
// A concurrent
|
|
739
|
-
// that is the idempotent outcome, not a failure.
|
|
536
|
+
// A concurrent mint between list and create is success.
|
|
740
537
|
const raced = /label\b[\s\S]*?already exists/i.test(
|
|
741
538
|
`${res.stderr ?? ''}${res.spawnError?.message ?? ''}`,
|
|
742
539
|
);
|
|
@@ -753,12 +550,7 @@ export async function ensureIssueLabels({
|
|
|
753
550
|
return { created, missing, errors };
|
|
754
551
|
}
|
|
755
552
|
|
|
756
|
-
/**
|
|
757
|
-
* File a new follow-up issue via `gh issue create` and resolve to
|
|
758
|
-
* `{ url, error }`. On success `url` is the trimmed stdout and `error` is
|
|
759
|
-
* null; on failure `url` is null and `error` carries a human-readable
|
|
760
|
-
* message.
|
|
761
|
-
*/
|
|
553
|
+
/** Resolves `{ url, error }`; exactly one is non-null. */
|
|
762
554
|
export async function createFollowUpIssue({
|
|
763
555
|
owner,
|
|
764
556
|
repo,
|
|
@@ -797,16 +589,9 @@ export async function createFollowUpIssue({
|
|
|
797
589
|
}
|
|
798
590
|
|
|
799
591
|
/**
|
|
800
|
-
*
|
|
801
|
-
*
|
|
802
|
-
*
|
|
803
|
-
* `graduate` so the orchestrating body holds no guard-chain branching.
|
|
804
|
-
*
|
|
805
|
-
* Story #5003 dropped the `provider.getTicketComments` gate with the
|
|
806
|
-
* structured-comment read limb. The provider is now consulted only by the
|
|
807
|
-
* best-effort cross-repo-deferred upsert, which reports its own faults into
|
|
808
|
-
* `errors[]` — gating the whole walk on a shape only that path needs would
|
|
809
|
-
* refuse work the walk can complete.
|
|
592
|
+
* `null` when all pass, else a partial envelope to short-circuit on. The
|
|
593
|
+
* provider is deliberately not gated: only the best-effort cross-repo upsert
|
|
594
|
+
* needs it, and that reports its own faults.
|
|
810
595
|
*/
|
|
811
596
|
function checkGraduatePreconditions({ epicId, currentRepo, config, spec }) {
|
|
812
597
|
if (!spec.isAutoFileEnabled(config)) {
|
|
@@ -826,16 +611,9 @@ function checkGraduatePreconditions({ epicId, currentRepo, config, spec }) {
|
|
|
826
611
|
}
|
|
827
612
|
|
|
828
613
|
/**
|
|
829
|
-
*
|
|
830
|
-
*
|
|
831
|
-
*
|
|
832
|
-
* content-hash marker is passed in precomputed so a caller can consult an
|
|
833
|
-
* in-process memo before spending a spawn.
|
|
834
|
-
*
|
|
835
|
-
* Resolves `{ alreadyFiled, existing }` — `existing` carries the matched
|
|
836
|
-
* issue's `{ number, state, url }` when the search index surfaced it, so a
|
|
837
|
-
* recurrence can update that issue rather than only knowing that one exists.
|
|
838
|
-
* `existing` is `null` on the not-found path.
|
|
614
|
+
* Checks the content-hash marker, then the legacy ordinal marker so
|
|
615
|
+
* pre-fingerprint filings are not re-filed. `existing` identifies the match
|
|
616
|
+
* so a recurrence can update it.
|
|
839
617
|
*/
|
|
840
618
|
async function resolveAlreadyFiled({
|
|
841
619
|
finding,
|
|
@@ -861,8 +639,6 @@ async function resolveAlreadyFiled({
|
|
|
861
639
|
|
|
862
640
|
const hit = await probe(contentMarker);
|
|
863
641
|
if (hit) return { alreadyFiled: true, existing: hit };
|
|
864
|
-
// Legacy recognition — a pre-cutover follow-up carries the ordinal
|
|
865
|
-
// marker, not the content hash. Skip re-filing when it is present.
|
|
866
642
|
if (typeof spec.buildLegacyMarker === 'function') {
|
|
867
643
|
const legacyMarker = spec.buildLegacyMarker(epicId, finding.index);
|
|
868
644
|
if (legacyMarker) {
|
|
@@ -874,18 +650,9 @@ async function resolveAlreadyFiled({
|
|
|
874
650
|
}
|
|
875
651
|
|
|
876
652
|
/**
|
|
877
|
-
*
|
|
878
|
-
* (
|
|
879
|
-
*
|
|
880
|
-
* An **open** issue with a resolvable number is refreshed in place and
|
|
881
|
-
* recorded on `envelope.filed` with `action: 'updated'` — same array as a
|
|
882
|
-
* creation, because both are live writes this run performed and the roll-up
|
|
883
|
-
* that reports "filed" must count them alike.
|
|
884
|
-
*
|
|
885
|
-
* Anything else records `already-filed` and touches nothing: a closed
|
|
886
|
-
* follow-up is a decided one (reopening it would relitigate a human's call),
|
|
887
|
-
* and an unresolvable number or state is not licence to edit an issue we
|
|
888
|
-
* cannot identify.
|
|
653
|
+
* An open, numbered match is refreshed and recorded on `filed` as
|
|
654
|
+
* `action: 'updated'` (a live write, counted like a creation). Anything else
|
|
655
|
+
* is `already-filed` and untouched: a closed follow-up is a human's decision.
|
|
889
656
|
*
|
|
890
657
|
* @returns {Promise<boolean>} `true` when the recurrence was handled here.
|
|
891
658
|
*/
|
|
@@ -941,13 +708,6 @@ async function resolveFollowUpRecurrence({
|
|
|
941
708
|
return true;
|
|
942
709
|
}
|
|
943
710
|
|
|
944
|
-
/**
|
|
945
|
-
* Route a single finding (path-exists probe → repo routing → idempotency
|
|
946
|
-
* probe → cap → file) and fold the outcome into the running envelope. Story
|
|
947
|
-
* #4075 extracted this from `graduate`'s per-finding loop; Story #4415
|
|
948
|
-
* hardened it (path-less seam, probe-error distinction, legacy-marker
|
|
949
|
-
* recognition, filing cap, and cross-repo-deferred collection).
|
|
950
|
-
*/
|
|
951
711
|
async function processGraduateFinding({
|
|
952
712
|
finding,
|
|
953
713
|
envelope,
|
|
@@ -981,9 +741,7 @@ async function processGraduateFinding({
|
|
|
981
741
|
),
|
|
982
742
|
);
|
|
983
743
|
|
|
984
|
-
//
|
|
985
|
-
// the path-exists gate does not apply — probing an empty path would
|
|
986
|
-
// misclassify them `file-removed`. Only file-scoped findings are probed.
|
|
744
|
+
// A path-less finding would misclassify as `file-removed`; skip the probe.
|
|
987
745
|
const hasPath =
|
|
988
746
|
typeof finding.path === 'string' && finding.path.trim().length > 0;
|
|
989
747
|
if (hasPath) {
|
|
@@ -994,18 +752,13 @@ async function processGraduateFinding({
|
|
|
994
752
|
cwd,
|
|
995
753
|
timeoutMs,
|
|
996
754
|
});
|
|
997
|
-
// A probe failure is not proof the file is gone — record it distinctly
|
|
998
|
-
// so a transient git/spawn fault does not masquerade as a removal.
|
|
999
755
|
if (probeError) return skip('probe-error');
|
|
1000
756
|
if (!exists) return skip('file-removed');
|
|
1001
757
|
}
|
|
1002
758
|
|
|
1003
759
|
const source = classifier(finding.path, null);
|
|
1004
|
-
//
|
|
1005
|
-
//
|
|
1006
|
-
// framework slug to the CONSUMER's repo, silently filing framework-owned
|
|
1007
|
-
// work in the wrong place (see `github/framework-repo.js`). Unroutable
|
|
1008
|
-
// findings are deferred and named, never re-pointed.
|
|
760
|
+
// Unroutable findings are deferred and named, never re-pointed at the
|
|
761
|
+
// consumer's repo.
|
|
1009
762
|
const routing = routeOwnership({ bucket: source, repos, currentRepo });
|
|
1010
763
|
if (!routing.routable) {
|
|
1011
764
|
const logLine = `[${spec.fnName}] unroutable ${source} finding (${routing.missingKey} is unset) — not filed: ${finding.title ?? finding.path ?? `finding ${finding.index}`}`;
|
|
@@ -1029,11 +782,7 @@ async function processGraduateFinding({
|
|
|
1029
782
|
|
|
1030
783
|
const contentMarker = spec.buildContentMarker(epicId, finding);
|
|
1031
784
|
|
|
1032
|
-
// In-process memo
|
|
1033
|
-
// invocation — e.g. the framework bucket of a retro rollup that also has
|
|
1034
|
-
// the same category in the consumer bucket — short-circuits a repeat in a
|
|
1035
|
-
// later bucket without spending a single spawn, and closes the same-rollup
|
|
1036
|
-
// race the eventually-consistent search index cannot.
|
|
785
|
+
// In-process memo closes the same-invocation race the search index cannot.
|
|
1037
786
|
if (filedMarkers?.has(contentMarker)) return skip('already-filed');
|
|
1038
787
|
|
|
1039
788
|
const { alreadyFiled, existing } = await resolveAlreadyFiled({
|
|
@@ -1048,10 +797,8 @@ async function processGraduateFinding({
|
|
|
1048
797
|
spec,
|
|
1049
798
|
});
|
|
1050
799
|
|
|
1051
|
-
//
|
|
1052
|
-
//
|
|
1053
|
-
// filing would carry (they agree with the marker by construction), and so
|
|
1054
|
-
// the recurrence path has the refreshed body to write.
|
|
800
|
+
// Built before dedup: the strong read scopes by these labels and a
|
|
801
|
+
// recurrence writes this body.
|
|
1055
802
|
const { title, body, labels } = spec.buildFollowUp({
|
|
1056
803
|
finding,
|
|
1057
804
|
source,
|
|
@@ -1078,15 +825,10 @@ async function processGraduateFinding({
|
|
|
1078
825
|
return;
|
|
1079
826
|
}
|
|
1080
827
|
|
|
1081
|
-
// Per-run filing cap — bounds the live writes this run performs. Checked
|
|
1082
|
-
// only on the would-file path: an `already-filed` finding resolved above
|
|
1083
|
-
// never reaches here. The excess is surfaced so a re-run picks it up.
|
|
1084
828
|
if (envelope.filed.length >= maxFilingsPerRun) return skip('cap-reached');
|
|
1085
829
|
|
|
1086
|
-
//
|
|
1087
|
-
//
|
|
1088
|
-
// --label <absent>` exits 0 with `[]`, so an absent label silently degrades
|
|
1089
|
-
// the dedup confirm too, not just the filing.
|
|
830
|
+
// Before the strong read too: `gh issue list --label <absent>` exits 0
|
|
831
|
+
// with `[]`, silently defeating the dedup confirm.
|
|
1090
832
|
const ensured = await ensureIssueLabels({
|
|
1091
833
|
owner: routedRepo.owner,
|
|
1092
834
|
repo: routedRepo.repo,
|
|
@@ -1099,17 +841,9 @@ async function processGraduateFinding({
|
|
|
1099
841
|
});
|
|
1100
842
|
envelope.errors.push(...ensured.errors);
|
|
1101
843
|
if (ensured.missing.length > 0) {
|
|
1102
|
-
// `gh issue create` would reject the whole call on the absent name; say
|
|
1103
|
-
// which label blocked it rather than replaying an opaque CLI failure.
|
|
1104
844
|
return skip('label-ensure-failed');
|
|
1105
845
|
}
|
|
1106
846
|
|
|
1107
|
-
// Strong read (would-file path only, Story #4657): the search probe reads
|
|
1108
|
-
// an eventually-consistent index that can miss a byte-identical duplicate
|
|
1109
|
-
// filed seconds earlier. Confirm against a strongly-consistent,
|
|
1110
|
-
// label-scoped `gh issue list` before creating. Skipped entirely on the
|
|
1111
|
-
// already-filed path above, so it never fires when the search probe
|
|
1112
|
-
// already matched.
|
|
1113
847
|
const confirmed = await findExistingFollowUp({
|
|
1114
848
|
markers:
|
|
1115
849
|
typeof spec.buildMatchTokens === 'function'
|
|
@@ -1176,12 +910,6 @@ async function processGraduateFinding({
|
|
|
1176
910
|
);
|
|
1177
911
|
}
|
|
1178
912
|
|
|
1179
|
-
/**
|
|
1180
|
-
* Render the durable cross-repo-deferred comment body from the collected
|
|
1181
|
-
* deferrals. Each row names the finding path/severity plus the would-be
|
|
1182
|
-
* `gh issue create` command so an operator (or a later cross-repo pass)
|
|
1183
|
-
* can act on it.
|
|
1184
|
-
*/
|
|
1185
913
|
function renderCrossRepoDeferredBody(deferred, spec) {
|
|
1186
914
|
const header =
|
|
1187
915
|
spec.crossRepoCommentHeader ??
|
|
@@ -1191,8 +919,6 @@ function renderCrossRepoDeferredBody(deferred, spec) {
|
|
|
1191
919
|
typeof finding.path === 'string' && finding.path.length > 0
|
|
1192
920
|
? `\`${finding.path}\``
|
|
1193
921
|
: '_(no path)_';
|
|
1194
|
-
// An unroutable finding has no destination to name — say which config
|
|
1195
|
-
// key would give it one instead of inventing a repo for the row.
|
|
1196
922
|
const destination = routedRepo
|
|
1197
923
|
? `${routedRepo.owner}/${routedRepo.repo}`
|
|
1198
924
|
: `**unroutable** (\`${missingKey}\` is unset)`;
|
|
@@ -1204,12 +930,7 @@ function renderCrossRepoDeferredBody(deferred, spec) {
|
|
|
1204
930
|
return [header, '', ...rows].join('\n');
|
|
1205
931
|
}
|
|
1206
932
|
|
|
1207
|
-
/**
|
|
1208
|
-
* Durably persist the cross-repo-deferred findings as a structured comment
|
|
1209
|
-
* on the Epic (upserted — one comment per graduator, refreshed in place).
|
|
1210
|
-
* Best-effort: a provider that cannot post comments is a no-op, and an
|
|
1211
|
-
* upsert failure lands in `envelope.errors` rather than throwing.
|
|
1212
|
-
*/
|
|
933
|
+
/** Best-effort upsert; failures land in `envelope.errors`, never thrown. */
|
|
1213
934
|
async function persistCrossRepoDeferred({
|
|
1214
935
|
epicId,
|
|
1215
936
|
provider,
|
|
@@ -1235,74 +956,36 @@ async function persistCrossRepoDeferred({
|
|
|
1235
956
|
}
|
|
1236
957
|
|
|
1237
958
|
/**
|
|
1238
|
-
*
|
|
1239
|
-
*
|
|
1240
|
-
*
|
|
1241
|
-
* `
|
|
1242
|
-
*
|
|
1243
|
-
* Each finding MUST carry `{ severity, path, summary, index }` and MAY carry
|
|
1244
|
-
* additional fields (e.g. `category`) that the builders use.
|
|
1245
|
-
*
|
|
1246
|
-
* The per-graduator variation lives entirely in the injected callbacks:
|
|
1247
|
-
*
|
|
1248
|
-
* - `buildContentMarker(epicId, finding)` — the content-hash HTML-comment
|
|
1249
|
-
* marker embedded in (and searched for in) follow-up bodies.
|
|
1250
|
-
* - `buildLegacyMarker(epicId, index)` — the pre-cutover ordinal marker,
|
|
1251
|
-
* probed for idempotency so legacy filings are not duplicated.
|
|
1252
|
-
* - `buildMatchTokens({ epicId, finding, contentMarker })` — optional; the
|
|
1253
|
-
* body substrings the strong read accepts as proof of a prior filing.
|
|
1254
|
-
* Defaults to `[contentMarker]`. A graduator whose marker format changed
|
|
1255
|
-
* returns the old shape here too, so the cutover recognizes the backlog
|
|
1256
|
-
* it already filed instead of duplicating it.
|
|
1257
|
-
* - `buildFollowUp({ finding, source, epicId, idMarker })` — returns
|
|
1258
|
-
* `{ title, body, labels }` for the issue to file.
|
|
1259
|
-
* - `buildCrossRepoLog({ finding, routedRepo, source })` — returns the
|
|
1260
|
-
* human-readable would-be-command string for a cross-repo skip.
|
|
1261
|
-
* - `decorateRecord(record, finding)` — copies finding-specific fields
|
|
1262
|
-
* (e.g. `lens`) onto a `skipped`/`filed` record before it is pushed.
|
|
1263
|
-
* - `crossRepoCommentAttrs` — discriminator attrs for the durable
|
|
1264
|
-
* cross-repo-deferred comment (so the two graduators do not clobber
|
|
1265
|
-
* each other's comment).
|
|
959
|
+
* Never throws; every failure lands in `errors[]`. Each finding carries
|
|
960
|
+
* `{ severity, path, summary, index }`. `spec` supplies `buildContentMarker`,
|
|
961
|
+
* `buildLegacyMarker`, optional `buildMatchTokens` (strong-read substrings,
|
|
962
|
+
* default `[contentMarker]`), `buildFollowUp`, `buildCrossRepoLog`,
|
|
963
|
+
* `decorateRecord`, and `crossRepoCommentAttrs`.
|
|
1266
964
|
*
|
|
1267
965
|
* @param {object} opts
|
|
1268
966
|
* @param {number} opts.epicId
|
|
1269
|
-
* @param {object} opts.provider
|
|
1270
|
-
* the durable cross-repo-deferred persistence
|
|
967
|
+
* @param {object} opts.provider
|
|
1271
968
|
* @param {object} [opts.config]
|
|
1272
969
|
* @param {{owner: string, repo: string}} opts.currentRepo
|
|
1273
|
-
* @param {{owner: string, repo: string}} [opts.frameworkRepo] —
|
|
1274
|
-
*
|
|
1275
|
-
*
|
|
1276
|
-
* named rather than filed in the wrong tracker.
|
|
1277
|
-
* @param {{owner: string, repo: string}} [opts.platformRepo] — the shared
|
|
1278
|
-
* platform/infra bucket, for a caller whose classifier can reach it.
|
|
970
|
+
* @param {{owner: string, repo: string}} [opts.frameworkRepo] — absent means
|
|
971
|
+
* unroutable, never the consumer's repo.
|
|
972
|
+
* @param {{owner: string, repo: string}} [opts.platformRepo]
|
|
1279
973
|
* @param {string} [opts.gitRef='HEAD']
|
|
1280
974
|
* @param {Function} [opts.classifier=classifyPathSource]
|
|
1281
975
|
* @param {string} [opts.ghPath='gh']
|
|
1282
976
|
* @param {Function} [opts.spawnImpl]
|
|
1283
977
|
* @param {string} [opts.cwd]
|
|
1284
|
-
* @param {number} [opts.timeoutMs]
|
|
1285
|
-
* @param {number} [opts.maxFilingsPerRun]
|
|
1286
|
-
* @param {Array<object>} opts.findings —
|
|
1287
|
-
*
|
|
1288
|
-
*
|
|
1289
|
-
* @param {Set<string
|
|
1290
|
-
*
|
|
1291
|
-
*
|
|
1292
|
-
* buckets) so a marker filed in one call short-circuits a repeat in the
|
|
1293
|
-
* next without a spawn. Defaults to a fresh per-call Set.
|
|
1294
|
-
* @param {Map<string, Set<string>>} [opts.labelCache] — per-repo memo of the
|
|
1295
|
-
* live label set, so the just-in-time label mint (Story #4828) costs one
|
|
1296
|
-
* `gh label list` per routed repo rather than one per finding. Share it
|
|
1297
|
-
* across the calls of one logical invocation, like `filedMarkers`.
|
|
1298
|
-
* @param {NodeJS.ProcessEnv} [opts.env] — injectable for the blast-radius
|
|
1299
|
-
* guard's context decision; defaults to `process.env`.
|
|
1300
|
-
* @param {string[]} [opts.execArgv] — ditto; defaults to `process.execArgv`.
|
|
978
|
+
* @param {number} [opts.timeoutMs]
|
|
979
|
+
* @param {number} [opts.maxFilingsPerRun]
|
|
980
|
+
* @param {Array<object>} opts.findings — a non-array is an error, not a no-op.
|
|
981
|
+
* @param {Set<string>} [opts.filedMarkers] — share across calls of one
|
|
982
|
+
* invocation so a repeat short-circuits without a spawn.
|
|
983
|
+
* @param {Map<string, Set<string>>} [opts.labelCache] — share likewise.
|
|
984
|
+
* @param {NodeJS.ProcessEnv} [opts.env]
|
|
985
|
+
* @param {string[]} [opts.execArgv]
|
|
1301
986
|
* @param {{info?: Function, warn?: Function, debug?: Function}} [opts.logger]
|
|
1302
|
-
* @param {object} opts.spec
|
|
987
|
+
* @param {object} opts.spec
|
|
1303
988
|
* @returns {Promise<{ filed: object[], skipped: object[], errors: string[] }>}
|
|
1304
|
-
* Each `filed` record carries `action: 'created'|'updated'` — both are live
|
|
1305
|
-
* writes this run performed, so a roll-up counting "filed" counts both.
|
|
1306
989
|
*/
|
|
1307
990
|
export async function graduate({
|
|
1308
991
|
epicId,
|
|
@@ -1340,10 +1023,6 @@ export async function graduate({
|
|
|
1340
1023
|
});
|
|
1341
1024
|
if (precondition) return { ...envelope, ...precondition };
|
|
1342
1025
|
|
|
1343
|
-
// Pre-parsed findings are the only source (Story #5003). The
|
|
1344
|
-
// structured-comment read/parse limb went with the audit-results
|
|
1345
|
-
// graduator: it walked an Epic's `verification-results` comment, and v2
|
|
1346
|
-
// has no Epics, so it could only ever resolve zero findings.
|
|
1347
1026
|
if (!Array.isArray(preParsedFindings)) {
|
|
1348
1027
|
return {
|
|
1349
1028
|
...envelope,
|
|
@@ -1352,8 +1031,7 @@ export async function graduate({
|
|
|
1352
1031
|
}
|
|
1353
1032
|
const findings = preParsedFindings;
|
|
1354
1033
|
|
|
1355
|
-
//
|
|
1356
|
-
// first spawn, so a refused context costs no child process at all.
|
|
1034
|
+
// Decided once, before any spawn.
|
|
1357
1035
|
const filing = resolveFilingContext({
|
|
1358
1036
|
spawnImpl,
|
|
1359
1037
|
...(env === undefined ? {} : { env }),
|
|
@@ -1379,10 +1057,6 @@ export async function graduate({
|
|
|
1379
1057
|
return envelope;
|
|
1380
1058
|
}
|
|
1381
1059
|
|
|
1382
|
-
// The ownership map the routing SSOT resolves against. `platform` is
|
|
1383
|
-
// absent for both graduators today (their classifier is binary) and is
|
|
1384
|
-
// threaded so a caller that does know a shared-infra repo routes there
|
|
1385
|
-
// rather than into the nearest plausible tracker.
|
|
1386
1060
|
const repos = {
|
|
1387
1061
|
consumer: currentRepo,
|
|
1388
1062
|
framework: frameworkRepo ?? null,
|