mandrel 2.31.0 → 2.33.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 +13 -17
- package/.agents/agents/acceptance-critic.md +1 -2
- package/.agents/docs/SDLC.md +12 -9
- package/.agents/docs/agentrc-reference.json +63 -58
- package/.agents/docs/configuration.md +275 -227
- package/.agents/docs/execution-reference.md +13 -14
- package/.agents/docs/quality-gates.md +195 -23
- package/.agents/instructions.md +2 -5
- package/.agents/rules/git-conventions-reference.md +27 -27
- package/.agents/rules/git-conventions.md +4 -2
- package/.agents/rules/known-tooling-behavior.md +66 -30
- package/.agents/rules/testing-standards.md +35 -71
- package/.agents/runtime-deps.json +2 -2
- package/.agents/schemas/agentrc.schema.json +1955 -1410
- package/.agents/schemas/lifecycle/README.md +21 -14
- package/.agents/schemas/lifecycle/ledger-record.schema.json +76 -22
- package/.agents/schemas/story-deliver-terminal.schema.json +2 -2
- package/.agents/scripts/README.md +16 -29
- package/.agents/scripts/apply-quality-bootstrap.js +27 -34
- package/.agents/scripts/audit-to-stories.js +160 -41
- package/.agents/scripts/bootstrap.js +28 -26
- package/.agents/scripts/check-baseline-drift.js +73 -13
- package/.agents/scripts/check-baseline-scope.js +362 -0
- package/.agents/scripts/check-dead-exports.js +9 -1
- package/.agents/scripts/check-gherkin-corpus.js +508 -0
- package/.agents/scripts/check-knip-entries.js +159 -0
- package/.agents/scripts/check-lifecycle-lint.js +108 -124
- package/.agents/scripts/check-schema-references.js +1 -1
- package/.agents/scripts/diagnose-friction.js +7 -4
- package/.agents/scripts/generate-config-docs.js +263 -171
- package/.agents/scripts/install-matrix-assert.js +0 -1
- package/.agents/scripts/lib/ITicketingProvider.js +0 -58
- package/.agents/scripts/lib/audit-baselines/staleness.js +6 -6
- package/.agents/scripts/lib/audit-baselines/trend.js +7 -8
- package/.agents/scripts/lib/audit-baselines/weights.js +4 -5
- package/.agents/scripts/lib/audit-suite/checklist-threading.js +1 -1
- package/.agents/scripts/lib/audit-to-stories/build-story-body.js +81 -35
- package/.agents/scripts/lib/audit-to-stories/wire-dependencies.js +185 -0
- package/.agents/scripts/lib/baselines/envelope.js +41 -60
- package/.agents/scripts/lib/baselines/git-base.js +30 -37
- package/.agents/scripts/lib/baselines/kinds/_crap-new-method-gate.js +103 -0
- package/.agents/scripts/lib/baselines/kinds/_crap-read.js +150 -0
- package/.agents/scripts/lib/baselines/kinds/crap.js +25 -65
- package/.agents/scripts/lib/baselines/orphan-pruner.js +233 -0
- package/.agents/scripts/lib/baselines/refresh-service.js +6 -8
- package/.agents/scripts/lib/baselines/scope-assert.js +223 -0
- package/.agents/scripts/lib/baselines/scope-inventory.js +314 -0
- package/.agents/scripts/lib/bdd-step-index.js +326 -0
- package/.agents/scripts/lib/bootstrap/install-ledger.js +5 -3
- package/.agents/scripts/lib/bootstrap/issue-forms-template.js +4 -6
- package/.agents/scripts/lib/bootstrap/manifest.js +17 -40
- package/.agents/scripts/lib/bootstrap/project-bootstrap.js +12 -59
- package/.agents/scripts/lib/bootstrap/quality-bootstrap.js +62 -2
- package/.agents/scripts/lib/checks/loop-health.js +9 -37
- package/.agents/scripts/lib/child-exec.js +193 -0
- package/.agents/scripts/lib/cli/standard-args.js +1 -1
- package/.agents/scripts/lib/cli-args.js +64 -0
- package/.agents/scripts/lib/close-validation/gates.js +2 -2
- package/.agents/scripts/lib/close-validation/runner.js +3 -3
- package/.agents/scripts/lib/config/acceptance-eval.js +5 -52
- package/.agents/scripts/lib/config/commands.js +3 -5
- package/.agents/scripts/lib/config/explain.js +5 -7
- package/.agents/scripts/lib/config/gates/bundle-size.schema.js +32 -6
- package/.agents/scripts/lib/config/gates/coverage.schema.js +25 -5
- package/.agents/scripts/lib/config/gates/crap-incremental-coverage.schema.js +12 -2
- package/.agents/scripts/lib/config/gates/crap.schema.js +68 -23
- package/.agents/scripts/lib/config/gates/duplication.schema.js +29 -17
- package/.agents/scripts/lib/config/gates/index.js +5 -2
- package/.agents/scripts/lib/config/gates/lighthouse.schema.js +34 -6
- package/.agents/scripts/lib/config/gates/lint.schema.js +11 -2
- package/.agents/scripts/lib/config/gates/maintainability.schema.js +37 -15
- package/.agents/scripts/lib/config/gates/mutation.schema.js +15 -3
- package/.agents/scripts/lib/config/gates/shared.js +58 -9
- package/.agents/scripts/lib/config/github.js +0 -1
- package/.agents/scripts/lib/config/limits.js +3 -48
- package/.agents/scripts/lib/config/qa.js +105 -0
- package/.agents/scripts/lib/config/runners.js +38 -16
- package/.agents/scripts/lib/config/temp-paths.js +6 -5
- package/.agents/scripts/lib/config-settings-schema-delivery.js +245 -56
- package/.agents/scripts/lib/config-settings-schema-quality.js +209 -29
- package/.agents/scripts/lib/config-settings-schema.js +386 -39
- package/.agents/scripts/lib/crap-baseline-join.js +126 -9
- package/.agents/scripts/lib/crap-utils.js +84 -520
- package/.agents/scripts/lib/dead-exports-knip.js +79 -10
- package/.agents/scripts/lib/degraded-mode.js +2 -2
- package/.agents/scripts/lib/dependency-parser.js +20 -7
- package/.agents/scripts/lib/doc-tiers.js +3 -3
- package/.agents/scripts/lib/feedback-loop/graduator-core.js +46 -104
- package/.agents/scripts/lib/feedback-loop/retro-proposals-graduator.js +10 -8
- package/.agents/scripts/lib/findings/provenance-field.js +135 -0
- package/.agents/scripts/lib/findings/route-finding.js +57 -8
- package/.agents/scripts/lib/fs-walk.js +52 -0
- package/.agents/scripts/lib/git-branch-lifecycle.js +2 -2
- package/.agents/scripts/lib/git-utils.js +16 -36
- package/.agents/scripts/lib/knip-config-resolver.js +181 -0
- package/.agents/scripts/lib/knip-entry-sync.js +508 -0
- package/.agents/scripts/lib/observability/metrics-ledger.js +1 -1
- package/.agents/scripts/lib/observability/runtime-friction.js +10 -0
- package/.agents/scripts/lib/observability/signal-validator.js +5 -85
- package/.agents/scripts/lib/observability/signals-writer.js +19 -62
- package/.agents/scripts/lib/observability/source-classifier.js +5 -7
- package/.agents/scripts/lib/observability/terse-result.js +3 -3
- package/.agents/scripts/lib/orchestration/behind-recovery.js +114 -0
- package/.agents/scripts/lib/orchestration/ceremony-routing.js +7 -8
- package/.agents/scripts/lib/orchestration/ci-rerun-guard.js +34 -33
- package/.agents/scripts/lib/orchestration/code-review.js +2 -2
- package/.agents/scripts/lib/orchestration/complexity-gate.js +43 -161
- package/.agents/scripts/lib/orchestration/diff-magnitude.js +4 -4
- package/.agents/scripts/lib/orchestration/label-transitions.js +3 -2
- package/.agents/scripts/lib/orchestration/lease-guard-shared.js +12 -38
- package/.agents/scripts/lib/orchestration/lifecycle/emit-merge-unlanded.js +5 -6
- package/.agents/scripts/lib/orchestration/plan-metrics.js +2 -3
- package/.agents/scripts/lib/orchestration/plan-persist/persist-helpers.js +7 -26
- package/.agents/scripts/lib/orchestration/plan-persist/run-plan-persist.js +69 -5
- package/.agents/scripts/lib/orchestration/plan-persist/story-ops.js +69 -13
- package/.agents/scripts/lib/orchestration/plan-persist/summary.js +49 -0
- package/.agents/scripts/lib/orchestration/{lifecycle/listeners/watcher.js → pr-watch.js} +58 -208
- package/.agents/scripts/lib/orchestration/resolve-stories.js +77 -50
- package/.agents/scripts/lib/orchestration/review-providers/codex.js +1 -1
- package/.agents/scripts/lib/orchestration/review-providers/mi-exemptions.js +130 -0
- package/.agents/scripts/lib/orchestration/review-providers/native.js +30 -16
- package/.agents/scripts/lib/orchestration/single-story-close/phases/code-review.js +1 -1
- package/.agents/scripts/lib/orchestration/single-story-close/phases/confirm-merge.js +37 -26
- package/.agents/scripts/lib/orchestration/single-story-close/phases/conventional-subject.js +376 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/normalize-pr-title.js +161 -151
- package/.agents/scripts/lib/orchestration/single-story-close/phases/options.js +15 -3
- package/.agents/scripts/lib/orchestration/single-story-close/phases/pull-request.js +10 -15
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-block.js +5 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/review-override.js +157 -0
- package/.agents/scripts/lib/orchestration/single-story-close/phases/worktree-reap.js +0 -14
- package/.agents/scripts/lib/orchestration/single-story-close/runner.js +59 -25
- package/.agents/scripts/lib/orchestration/single-story-lease-guard.js +20 -31
- package/.agents/scripts/lib/orchestration/spec-spill.js +17 -3
- package/.agents/scripts/lib/orchestration/story-close/phases/review-core.js +7 -6
- package/.agents/scripts/lib/orchestration/story-deliver-terminal.js +2 -1
- package/.agents/scripts/lib/orchestration/task-body-validator.js +4 -1
- package/.agents/scripts/lib/orchestration/ticket-lease.js +28 -127
- package/.agents/scripts/lib/orchestration/ticket-validator-conflicts.js +116 -1
- package/.agents/scripts/lib/orchestration/ticket-validator-sizing.js +1 -1
- package/.agents/scripts/lib/orchestration/ticket-validator.js +38 -0
- package/.agents/scripts/lib/orchestration/ticketing/reads.js +5 -5
- package/.agents/scripts/lib/orchestration/ticketing/transition.js +5 -4
- package/.agents/scripts/lib/orchestration/verify-tier-repair.js +107 -0
- package/.agents/scripts/lib/qa/coverage-verdict.js +5 -87
- package/.agents/scripts/lib/signals/detectors/common.js +1 -1
- package/.agents/scripts/lib/signals/index.js +8 -6
- package/.agents/scripts/lib/signals/schema.js +20 -25
- package/.agents/scripts/lib/signals/write.js +8 -8
- package/.agents/scripts/lib/story-body/footer-block.js +97 -0
- package/.agents/scripts/lib/story-body/story-body.js +18 -81
- package/.agents/scripts/lib/temp-retention.js +1 -1
- package/.agents/scripts/lib/templates/decomposer-prompts.js +16 -14
- package/.agents/scripts/lib/ticket-body-sections.js +4 -5
- package/.agents/scripts/lib/wave-runner/footprint.js +306 -0
- package/.agents/scripts/lib/wave-runner/ready-set.js +198 -181
- package/.agents/scripts/lib/worktree/lifecycle/merge-reachability.js +13 -45
- package/.agents/scripts/lib/worktree/lifecycle/reap.js +4 -5
- package/.agents/scripts/lib/worktree-manager.js +2 -3
- package/.agents/scripts/lint-label-vocabulary.js +2 -24
- package/.agents/scripts/pr-watch-with-update.js +7 -5
- package/.agents/scripts/providers/github/blocked-by-add.js +25 -10
- package/.agents/scripts/providers/github/cache.js +2 -2
- package/.agents/scripts/providers/github/comments.js +6 -28
- package/.agents/scripts/providers/github/compose.js +0 -15
- package/.agents/scripts/providers/github/errors.js +10 -27
- package/.agents/scripts/providers/github/request-helpers.js +1 -2
- package/.agents/scripts/providers/github/sub-issues.js +10 -218
- package/.agents/scripts/providers/github.js +4 -7
- package/.agents/scripts/prune-baseline-orphans.js +181 -0
- package/.agents/scripts/resolve-stories.js +21 -7
- package/.agents/scripts/run-lint.js +61 -61
- package/.agents/scripts/run-test-profile.js +6 -6
- package/.agents/scripts/run-verify.js +48 -30
- package/.agents/scripts/single-story-close.js +20 -0
- package/.agents/scripts/single-story-init.js +12 -35
- package/.agents/scripts/stories-wave-tick.js +192 -9
- package/.agents/scripts/update-dead-exports-baseline.js +321 -0
- package/.agents/skills/core/gates-and-baselines/SKILL.md +2 -2
- package/.agents/skills/skills.index.json +1 -11
- package/.agents/workflows/audit-documentation.md +5 -6
- package/.agents/workflows/audit-to-stories.md +28 -2
- package/.agents/workflows/helpers/audit-lens-core.md +11 -12
- package/.agents/workflows/helpers/code-quality-guardrails.md +15 -14
- package/.agents/workflows/helpers/code-review.md +3 -8
- package/.agents/workflows/helpers/deliver-reference.md +30 -2
- package/.agents/workflows/helpers/deliver-story-reference.md +84 -16
- package/.agents/workflows/helpers/plan-reference.md +76 -0
- package/.agents/workflows/helpers/worktree-lifecycle.md +1 -2
- package/.agents/workflows/mandrel-update.md +10 -10
- package/.agents/workflows/qa-assist.md +15 -20
- package/.agents/workflows/qa-explore.md +9 -8
- package/README.md +1 -1
- package/docs/CHANGELOG.md +58 -0
- package/lib/migrations/index.js +2 -0
- package/lib/migrations/steps/2.32.0-retire-lint-baseline-command.js +127 -0
- package/package.json +14 -5
- package/.agents/schemas/lifecycle/checkpoint.written.schema.json +0 -13
- package/.agents/schemas/lifecycle/close-validate.end.schema.json +0 -18
- package/.agents/schemas/lifecycle/close-validate.start.schema.json +0 -13
- package/.agents/schemas/lifecycle/code-review.end.schema.json +0 -30
- package/.agents/schemas/lifecycle/code-review.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/intervention.recorded.schema.json +0 -15
- package/.agents/schemas/lifecycle/loop.tick.schema.json +0 -20
- package/.agents/schemas/lifecycle/notification.emitted.schema.json +0 -18
- package/.agents/schemas/lifecycle/pr.created.schema.json +0 -14
- package/.agents/schemas/lifecycle/retro.end.schema.json +0 -16
- package/.agents/schemas/lifecycle/retro.start.schema.json +0 -12
- package/.agents/schemas/lifecycle/story.blocked.schema.json +0 -13
- package/.agents/schemas/lifecycle/story.dispatch.end.schema.json +0 -17
- package/.agents/schemas/lifecycle/story.dispatch.start.schema.json +0 -15
- package/.agents/schemas/lifecycle/story.merged.schema.json +0 -13
- package/.agents/scripts/check-gherkin-placeholders.js +0 -663
- package/.agents/scripts/check-lifecycle-doc-drift.js +0 -411
- package/.agents/scripts/lib/audit-suite/cli.js +0 -64
- package/.agents/scripts/lib/bootstrap/baselines-layout-migration.js +0 -202
- package/.agents/scripts/lib/bootstrap/ci-workflow-template.js +0 -212
- package/.agents/scripts/lib/checks/baseline-drift-main-checkout.js +0 -104
- package/.agents/scripts/lib/checks/push-hook-parity.js +0 -106
- package/.agents/scripts/lib/checks/windows-coverage-noise-floor.js +0 -92
- package/.agents/scripts/lib/checks/worktree-bootstrap-env.js +0 -81
- package/.agents/scripts/lib/checks/worktree-residue-biome.js +0 -55
- package/.agents/scripts/lib/crap-baseline-index.js +0 -46
- package/.agents/scripts/lib/crap-utils-incremental.js +0 -113
- package/.agents/scripts/lib/dynamic-workflow/capability.js +0 -396
- package/.agents/scripts/lib/feedback-loop/audit-results-graduator.js +0 -335
- package/.agents/scripts/lib/mutation/baseline-snapshot.js +0 -239
- package/.agents/scripts/lib/mutation/config-detector.js +0 -119
- package/.agents/scripts/lib/mutation/stryker-runner.js +0 -306
- package/.agents/scripts/lib/mutation/survivor-report.js +0 -160
- package/.agents/scripts/lib/observability/active-story-env.js +0 -170
- package/.agents/scripts/lib/observability/tool-trace-hook.js +0 -456
- package/.agents/scripts/lib/orchestration/acceptance-clusters.js +0 -111
- package/.agents/scripts/lib/orchestration/context-envelope.js +0 -277
- package/.agents/scripts/lib/orchestration/detectors-phase.js +0 -194
- package/.agents/scripts/lib/orchestration/lifecycle/bus.js +0 -309
- package/.agents/scripts/lib/orchestration/lifecycle/emit-loop-tick.js +0 -181
- package/.agents/scripts/lib/orchestration/lifecycle/ledger-writer.js +0 -229
- package/.agents/scripts/lib/orchestration/lifecycle/listeners/README.md +0 -54
- package/.agents/scripts/lib/orchestration/lifecycle/trace-logger.js +0 -344
- package/.agents/scripts/lib/orchestration/lint-baseline-service.js +0 -114
- package/.agents/scripts/lib/orchestration/pr-base-guard.js +0 -37
- package/.agents/scripts/lib/orchestration/resolves-token.js +0 -127
- package/.agents/scripts/lib/orchestration/spec-section-validator.js +0 -130
- package/.agents/scripts/lib/orchestration/story-close/emit-blocked.js +0 -55
- package/.agents/scripts/lib/orchestration/story-close/phases/code-review.js +0 -211
- package/.agents/scripts/lib/planning-corpus.js +0 -37
- package/.agents/scripts/lib/qa/coverage-report.js +0 -181
- package/.agents/scripts/lib/qa/propose-missing-test.js +0 -95
- package/.agents/scripts/lib/qa/qa-context-hydrator.js +0 -217
- package/.agents/scripts/lib/signals/detectors/index.js +0 -14
- package/.agents/scripts/lib/signals/detectors/retry.js +0 -253
- package/.agents/scripts/lib/signals/detectors/rework.js +0 -167
- package/.agents/scripts/lib/signals/read.js +0 -268
- package/.agents/scripts/lib/signals/span-tree.js +0 -291
- package/.agents/scripts/lib/story-lifecycle.js +0 -194
- package/.agents/scripts/lib/story-plan.js +0 -379
- package/.agents/scripts/lib/util/phase-timer-state.js +0 -72
- package/.agents/scripts/lib/util/phase-timer.js +0 -163
- package/.agents/scripts/lib/workers/combined-mi-crap-worker.js +0 -169
- package/.agents/scripts/lint-baseline.js +0 -507
- package/.agents/scripts/providers/github/prs.js +0 -103
- package/.agents/scripts/signals-view.js +0 -309
- package/.agents/scripts/story-plan.js +0 -370
- package/.agents/scripts/sync-branch-from-base.js +0 -149
- package/.agents/scripts/validate-docs-freshness.js +0 -314
- package/.agents/skills/core/diagnose-friction/SKILL.md +0 -78
- package/.agents/workflows/helpers/signals.md +0 -112
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveListValue } from '../config/shared.js';
|
|
1
2
|
import { parse as parseStoryBody } from '../story-body/story-body.js';
|
|
2
3
|
import { collectStoryAssumptionEntries } from './file-assumptions.js';
|
|
3
4
|
import { computeStoryReachability } from './story-reachability.js';
|
|
@@ -108,8 +109,11 @@ const DEFAULT_POLICY = Object.freeze({
|
|
|
108
109
|
* Patterns support two shapes:
|
|
109
110
|
* - exact path — `lib/orchestration/lifecycle/listeners/index.js`
|
|
110
111
|
* - `**` suffix — `**\/listeners/index.js` (matches any depth)
|
|
112
|
+
*
|
|
113
|
+
* Module-private since `resolveConflictPolicy` became the one production
|
|
114
|
+
* reader; tests reach it through `_internal`.
|
|
111
115
|
*/
|
|
112
|
-
|
|
116
|
+
const DEFAULT_REGISTRY_PATTERNS = Object.freeze([
|
|
113
117
|
'lib/orchestration/lifecycle/listeners/index.js',
|
|
114
118
|
'**/listeners/index.js',
|
|
115
119
|
'**/handlers/index.js',
|
|
@@ -762,6 +766,117 @@ export function computeConflictFindings({ stories, policy } = {}) {
|
|
|
762
766
|
];
|
|
763
767
|
}
|
|
764
768
|
|
|
769
|
+
/**
|
|
770
|
+
* Resolve the config-derived half of the conflict policy from
|
|
771
|
+
* `config.planning` — the severity flags, the fan-out threshold, and the
|
|
772
|
+
* registry patterns, in one place.
|
|
773
|
+
*
|
|
774
|
+
* Two passes consume `planning.*` and must not disagree: the raw
|
|
775
|
+
* pre-assembly pass (`persist-helpers.validateTickets`, which attaches its
|
|
776
|
+
* production `fanOutCounter` on top of this) and the post-assembly pass
|
|
777
|
+
* (`computeAssembledConflictFindings`, which forces `fanOutCounter: null`).
|
|
778
|
+
* Under Story #5045 each resolved its own copy, and the copies had already
|
|
779
|
+
* drifted — `failOnMissingBddScaffold` reached only the assembled pass,
|
|
780
|
+
* `failOnLargeFanOut` / `largeFanOutThreshold` / `crossCuttingRegistries`
|
|
781
|
+
* only the raw one — so a knob set in config silently applied on one of the
|
|
782
|
+
* two passes. A knob read here reaches both; that is the contract.
|
|
783
|
+
*
|
|
784
|
+
* `fanOutCounter` is deliberately absent: it is probe machinery, not
|
|
785
|
+
* config, and each caller owns its own.
|
|
786
|
+
*
|
|
787
|
+
* @param {object} [config] Resolved config carrying `planning.*`.
|
|
788
|
+
* @returns {object} A `computeConflictFindings` policy (no `fanOutCounter`).
|
|
789
|
+
*/
|
|
790
|
+
export function resolveConflictPolicy(config) {
|
|
791
|
+
const planning = config?.planning;
|
|
792
|
+
const policy = {
|
|
793
|
+
failOnSharedEditors: planning?.failOnSharedEditors === true,
|
|
794
|
+
requireExplicitCrossStoryDeps:
|
|
795
|
+
planning?.requireExplicitCrossStoryDeps === true,
|
|
796
|
+
failOnRegistryConflicts: planning?.failOnRegistryConflicts === true,
|
|
797
|
+
failOnLargeFanOut: planning?.failOnLargeFanOut === true,
|
|
798
|
+
failOnMissingBddScaffold: planning?.failOnMissingBddScaffold === true,
|
|
799
|
+
};
|
|
800
|
+
if (Number.isFinite(planning?.largeFanOutThreshold)) {
|
|
801
|
+
policy.largeFanOutThreshold = planning.largeFanOutThreshold;
|
|
802
|
+
}
|
|
803
|
+
if (planning?.crossCuttingRegistries !== undefined) {
|
|
804
|
+
policy.registries = resolveListValue(
|
|
805
|
+
DEFAULT_REGISTRY_PATTERNS,
|
|
806
|
+
planning.crossCuttingRegistries,
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
return policy;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
/**
|
|
813
|
+
* Re-run the cross-Story conflict passes over the **assembled** Story bodies —
|
|
814
|
+
* the artifact persist actually writes (Story #5045).
|
|
815
|
+
*
|
|
816
|
+
* `validateTickets` runs before `assemblePlanStories`, over the raw
|
|
817
|
+
* `stories.json` payload, so plan-time conflict analysis never saw what got
|
|
818
|
+
* persisted. That is not a cosmetic ordering nit: the canonical authoring shape
|
|
819
|
+
* carries `acceptance[]` / `verify[]` at the ticket's **top level**, and it is
|
|
820
|
+
* assembly's `syncContractFieldFromTopLevel` that folds them into the body.
|
|
821
|
+
* `indexConsumers` scans `body.acceptance` / `body.verify` for producer paths —
|
|
822
|
+
* so on the real payload it scanned two empty arrays, and every
|
|
823
|
+
* `implicit-cross-story-dep` and `missing-bdd-scaffold` finding was silently
|
|
824
|
+
* unreachable. Running the passes again over the serialized bodies restores
|
|
825
|
+
* them.
|
|
826
|
+
*
|
|
827
|
+
* **The fan-out pass is deliberately not re-run.** It is a `git grep` per
|
|
828
|
+
* deleted path and its inputs (`changes[]` deletes) are identical on both
|
|
829
|
+
* sides, so re-probing would double the git cost for a byte-identical answer;
|
|
830
|
+
* `enforceFanOutGate` already owns that class over the raw payload.
|
|
831
|
+
*
|
|
832
|
+
* @param {object} args
|
|
833
|
+
* @param {Array<{ slug: string, title?: string, body: string, depends_on?: string[] }>} args.stories
|
|
834
|
+
* Assembled Stories — `body` is the serialized, footer-stamped markdown.
|
|
835
|
+
* @param {object} [args.config] Resolved config; `planning.*` supplies the
|
|
836
|
+
* policy via {@link resolveConflictPolicy} — the same resolver the raw
|
|
837
|
+
* pass uses, so a knob cannot apply on only one of the two passes.
|
|
838
|
+
* @returns {ConflictFinding[]}
|
|
839
|
+
*/
|
|
840
|
+
export function computeAssembledConflictFindings({ stories, config } = {}) {
|
|
841
|
+
return computeConflictFindings({
|
|
842
|
+
stories: (Array.isArray(stories) ? stories : []).map((story) => ({
|
|
843
|
+
slug: story.slug,
|
|
844
|
+
title: story.title,
|
|
845
|
+
body: story.body,
|
|
846
|
+
depends_on: Array.isArray(story.depends_on) ? story.depends_on : [],
|
|
847
|
+
})),
|
|
848
|
+
policy: {
|
|
849
|
+
...resolveConflictPolicy(config),
|
|
850
|
+
fanOutCounter: null,
|
|
851
|
+
},
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* Stable identity for one conflict finding, so the post-assembly pass can be
|
|
857
|
+
* diffed against the raw pass and only the genuinely-new findings reported
|
|
858
|
+
* (Story #5045). Without it the two passes announce the same shared-editor
|
|
859
|
+
* collision twice per run, which is how a warning channel gets discounted.
|
|
860
|
+
*
|
|
861
|
+
* The separator is written as the `\u0000` escape and never as a raw byte — a
|
|
862
|
+
* literal NUL would make git classify this file as binary and drop its diffs.
|
|
863
|
+
*
|
|
864
|
+
* @param {object} finding
|
|
865
|
+
* @returns {string}
|
|
866
|
+
*/
|
|
867
|
+
export function conflictFindingKey(finding) {
|
|
868
|
+
return [
|
|
869
|
+
finding?.kind ?? '',
|
|
870
|
+
finding?.path ?? finding?.registryPath ?? '',
|
|
871
|
+
Array.isArray(finding?.storySlugs)
|
|
872
|
+
? [...finding.storySlugs].sort().join(',')
|
|
873
|
+
: (finding?.storySlug ?? ''),
|
|
874
|
+
finding?.producer?.storySlug ?? '',
|
|
875
|
+
finding?.consumer?.storySlug ?? '',
|
|
876
|
+
finding?.consumer?.sourceField ?? '',
|
|
877
|
+
].join('\u0000');
|
|
878
|
+
}
|
|
879
|
+
|
|
765
880
|
/**
|
|
766
881
|
* Render the audit trail behind a fan-out finding's number, so an operator
|
|
767
882
|
* can check the figure rather than trust it (Story #4547).
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
31
|
import { parse as parseStoryBody } from '../story-body/story-body.js';
|
|
32
|
-
import { estimateTokens } from './
|
|
32
|
+
import { estimateTokens } from './spec-spill.js';
|
|
33
33
|
|
|
34
34
|
/**
|
|
35
35
|
* Normalize a Story's `body` to the structured object the sizing layers
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ValidationError } from '../errors/index.js';
|
|
2
|
+
import { normalizeOwnedProvenance } from '../findings/provenance-field.js';
|
|
2
3
|
import { detectCycle } from '../Graph.js';
|
|
3
4
|
import { gitSpawn } from '../git-utils.js';
|
|
4
5
|
|
|
@@ -528,6 +529,41 @@ function assertEveryStoryHasInlineContract({ stories }) {
|
|
|
528
529
|
);
|
|
529
530
|
}
|
|
530
531
|
|
|
532
|
+
/**
|
|
533
|
+
* Shape-check the optional per-Story `provenance` field (Story #5045).
|
|
534
|
+
*
|
|
535
|
+
* The field decides which audit identities persist stamps into a Story body,
|
|
536
|
+
* so a malformed entry has to fail at the validator rather than at the
|
|
537
|
+
* stamper: by the time assembly runs, an unnoticed drop is indistinguishable
|
|
538
|
+
* from a Story that legitimately owns nothing — and the cost lands a whole
|
|
539
|
+
* sweep later, when the next audit re-files work this plan already tracked.
|
|
540
|
+
*
|
|
541
|
+
* Absence is valid and common: a Story with no `provenance` inherits the
|
|
542
|
+
* whole-seed union carry, which is the recall-safe default.
|
|
543
|
+
*
|
|
544
|
+
* Errors are batched across the backlog so one pass names every offender.
|
|
545
|
+
*
|
|
546
|
+
* @param {{ stories: object[] }} args
|
|
547
|
+
* @throws {Error} naming each malformed field.
|
|
548
|
+
*/
|
|
549
|
+
function assertStoryProvenanceShape({ stories }) {
|
|
550
|
+
const violations = [];
|
|
551
|
+
for (const story of stories) {
|
|
552
|
+
try {
|
|
553
|
+
normalizeOwnedProvenance(story?.provenance, story?.slug ?? '<unknown>');
|
|
554
|
+
} catch (err) {
|
|
555
|
+
violations.push(` - ${err.message}`);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
if (violations.length === 0) return;
|
|
559
|
+
throw new Error(
|
|
560
|
+
`Cross-Validation Failed: ${violations.length} Story provenance field(s) ` +
|
|
561
|
+
`are malformed:\n${violations.join('\n')}\n\nAuthor provenance as ` +
|
|
562
|
+
'{ "fingerprints": ["<40-char sha1>"], "semanticKeys": ["<area␟path>"] }, ' +
|
|
563
|
+
'or omit it entirely to inherit the seed-wide union.',
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
|
|
531
567
|
function assertNoUnknownDeps({ tickets, ticketBySlug }) {
|
|
532
568
|
const unknownDeps = [];
|
|
533
569
|
for (const t of tickets) {
|
|
@@ -575,6 +611,7 @@ export function validateAndNormalizeTickets(tickets, opts = {}) {
|
|
|
575
611
|
|
|
576
612
|
assertAllTicketsAreStories({ tickets, stories });
|
|
577
613
|
assertEveryStoryHasInlineContract({ stories });
|
|
614
|
+
assertStoryProvenanceShape({ stories });
|
|
578
615
|
assertNoUnknownDeps({ tickets, ticketBySlug });
|
|
579
616
|
|
|
580
617
|
assertAcyclic(slugAdjacency);
|
|
@@ -704,6 +741,7 @@ export const _internal = {
|
|
|
704
741
|
indexTicketsBySlug,
|
|
705
742
|
assertAllTicketsAreStories,
|
|
706
743
|
assertEveryStoryHasInlineContract,
|
|
744
|
+
assertStoryProvenanceShape,
|
|
707
745
|
assertNoUnknownDeps,
|
|
708
746
|
assertAcyclic,
|
|
709
747
|
attachFindingsAndErrors,
|
|
@@ -146,14 +146,14 @@ export const STRUCTURED_COMMENT_TYPES = Object.freeze([
|
|
|
146
146
|
// `--steal`, not by TTL expiry. One entry per ticket; re-acquires upsert
|
|
147
147
|
// in place.
|
|
148
148
|
'plan-lease',
|
|
149
|
-
// Story #4415 (Epic #4406) — the feedback-loop
|
|
150
|
-
// (`
|
|
151
|
-
// `cross-repo-deferred` comment
|
|
149
|
+
// Story #4415 (Epic #4406) — the feedback-loop graduator
|
|
150
|
+
// (`retro-proposals-graduator.js`) upserts a
|
|
151
|
+
// `cross-repo-deferred` comment listing findings that route
|
|
152
152
|
// to a different repository and were therefore not filed here. Replaces
|
|
153
153
|
// the prior log-line-only trace so the deferral survives the finalize
|
|
154
154
|
// run as a durable, operator-visible record. Discriminated by a
|
|
155
|
-
// `graduator="
|
|
156
|
-
//
|
|
155
|
+
// `graduator="<name>"` attr so independent graduators do not clobber each
|
|
156
|
+
// other's comment; re-runs upsert in place.
|
|
157
157
|
'cross-repo-deferred',
|
|
158
158
|
// Epic #4474 (PR3) / v2 Stage 3 — `plan-persist.js` upserts a single
|
|
159
159
|
// `plan-summary` comment on the primary Story at terminal persist
|
|
@@ -393,12 +393,13 @@ async function emitBlockedFriction(ticketId, fromState, newState, opts) {
|
|
|
393
393
|
* `agent::done` at story-close (after the merge lands), not when the
|
|
394
394
|
* last Task commit landed on the still-unmerged Story branch. The
|
|
395
395
|
* parameter is preserved for callers that still suppress cascade
|
|
396
|
-
* explicitly (
|
|
396
|
+
* explicitly (`single-story-init.js`, and `bulk.js` where the upward
|
|
397
|
+
* recursion is driven by hand instead).
|
|
397
398
|
*
|
|
398
399
|
* `ticketSnapshot` (Story #1795 / Epic #1788) is an optional pre-fetched
|
|
399
|
-
* ticket object. When the caller already holds the ticket
|
|
400
|
-
*
|
|
401
|
-
*
|
|
400
|
+
* ticket object. When the caller already holds the ticket — e.g. it
|
|
401
|
+
* hydrated the ticket to inspect its labels first — passing the
|
|
402
|
+
* snapshot eliminates the two `getTicket` round-trips that
|
|
402
403
|
* `transitionTicketState` would otherwise issue — one for the notify
|
|
403
404
|
* `fromState` lookup and one inside `provider.updateTicket`'s label
|
|
404
405
|
* merge path. Backwards compatible: when omitted, behaviour is unchanged.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* verify-tier-repair.js — repair-before-judging for the `verify[]` tier suffix
|
|
3
|
+
* (Story #5005).
|
|
4
|
+
*
|
|
5
|
+
* The tier suffix (`… (unit)`) is a deterministic, mechanically-derivable
|
|
6
|
+
* formality. `task-body-validator.js` already computed the corrected entry in
|
|
7
|
+
* order to print it as a "Suggested fix" — then rejected the plan anyway and
|
|
8
|
+
* charged the author a full re-drafting round to paste that exact string back.
|
|
9
|
+
* This module applies the inference the validator already trusts, so the hard
|
|
10
|
+
* error is reserved for the entries only the author can resolve.
|
|
11
|
+
*
|
|
12
|
+
* It lives beside the validator rather than inside it because the validator's
|
|
13
|
+
* job is to *judge*: mixing a mutating repair pass into a module of pure
|
|
14
|
+
* collectors muddies both. `persist-helpers.js#validateTickets` calls this
|
|
15
|
+
* first, then `validateTaskBodies`.
|
|
16
|
+
*
|
|
17
|
+
* @module lib/orchestration/verify-tier-repair
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { suggestVerifyFix } from '../story-body/body-format-lints.js';
|
|
21
|
+
import {
|
|
22
|
+
parse as parseStoryBody,
|
|
23
|
+
serialize as serializeStoryBody,
|
|
24
|
+
} from '../story-body/story-body.js';
|
|
25
|
+
import { VERIFY_TIER_VALUES } from './task-body-validator.js';
|
|
26
|
+
|
|
27
|
+
/** A parenthesised tier drawn from the canonical vocabulary, at end of entry. */
|
|
28
|
+
const VERIFY_TIER_RE = new RegExp(
|
|
29
|
+
`\\((?:${VERIFY_TIER_VALUES.join('|')})\\)\\s*$`,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Rewrite one `verify[]` list, appending the inferable testing tier to any
|
|
34
|
+
* entry missing one. Returns `null` when nothing changed, so callers can keep
|
|
35
|
+
* an already-compliant list byte-identical (and skip re-serializing the body
|
|
36
|
+
* it came from).
|
|
37
|
+
*
|
|
38
|
+
* @param {unknown} rawVerify
|
|
39
|
+
* @returns {string[]|null} The corrected list, or `null` when no fix applied.
|
|
40
|
+
*/
|
|
41
|
+
function repairVerifyList(rawVerify) {
|
|
42
|
+
if (!Array.isArray(rawVerify)) return null;
|
|
43
|
+
let changed = false;
|
|
44
|
+
const next = rawVerify.map((entry) => {
|
|
45
|
+
if (typeof entry !== 'string') return entry;
|
|
46
|
+
if (entry.startsWith('manual:') || VERIFY_TIER_RE.test(entry)) return entry;
|
|
47
|
+
const fix = suggestVerifyFix(entry);
|
|
48
|
+
if (fix === null) return entry;
|
|
49
|
+
changed = true;
|
|
50
|
+
return fix;
|
|
51
|
+
});
|
|
52
|
+
return changed ? next : null;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Repair the `## Verify` section of a serialized (string) body, in place on
|
|
57
|
+
* the ticket. Only re-serializes when a fix actually applied, so a compliant
|
|
58
|
+
* body is never round-tripped through `parse → serialize`.
|
|
59
|
+
*
|
|
60
|
+
* Leaving the body untouched while the top level was repaired would be worse
|
|
61
|
+
* than not repairing at all: `syncContractFieldFromTopLevel` fails closed on a
|
|
62
|
+
* body section that disagrees with its top-level array, so both sides must be
|
|
63
|
+
* repaired by the same rule or neither.
|
|
64
|
+
*
|
|
65
|
+
* @param {object} ticket
|
|
66
|
+
*/
|
|
67
|
+
function repairStringBodyVerify(ticket) {
|
|
68
|
+
let parsed;
|
|
69
|
+
try {
|
|
70
|
+
parsed = parseStoryBody(ticket.body).body;
|
|
71
|
+
} catch {
|
|
72
|
+
// An unparseable body is already a hard error in `validateTaskBodyShape`;
|
|
73
|
+
// there is nothing to repair and nothing to report twice.
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const repaired = repairVerifyList(parsed.verify);
|
|
77
|
+
if (repaired === null) return;
|
|
78
|
+
ticket.body = serializeStoryBody({ ...parsed, verify: repaired });
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Auto-append the testing tier to `verify[]` entries that omit one, wherever
|
|
83
|
+
* `suggestVerifyFix` can infer it from the command. An entry whose tier cannot
|
|
84
|
+
* be inferred is left untouched and still hard-errors downstream.
|
|
85
|
+
*
|
|
86
|
+
* Mutates `tickets` in place (the persist pipeline threads this same array on
|
|
87
|
+
* to assembly) and returns it. Already-compliant tickets are untouched, so
|
|
88
|
+
* their persisted output stays byte-identical. Total — a non-array argument
|
|
89
|
+
* and non-Story tickets are no-ops.
|
|
90
|
+
*
|
|
91
|
+
* @param {object[]} tickets
|
|
92
|
+
* @returns {object[]} `tickets`
|
|
93
|
+
*/
|
|
94
|
+
export function normalizeVerifyTiers(tickets) {
|
|
95
|
+
for (const ticket of Array.isArray(tickets) ? tickets : []) {
|
|
96
|
+
if (!ticket || ticket.type !== 'story' || ticket.body == null) continue;
|
|
97
|
+
const topLevel = repairVerifyList(ticket.verify);
|
|
98
|
+
if (topLevel !== null) ticket.verify = topLevel;
|
|
99
|
+
if (typeof ticket.body === 'string') {
|
|
100
|
+
repairStringBodyVerify(ticket);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
const bodyLevel = repairVerifyList(ticket.body.verify);
|
|
104
|
+
if (bodyLevel !== null) ticket.body.verify = bodyLevel;
|
|
105
|
+
}
|
|
106
|
+
return tickets;
|
|
107
|
+
}
|
|
@@ -34,17 +34,12 @@
|
|
|
34
34
|
// operator-facing string explaining the verdict (always populated,
|
|
35
35
|
// including for present tiers).
|
|
36
36
|
//
|
|
37
|
-
//
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
// }
|
|
41
|
-
//
|
|
42
|
-
// Maps each acceptance criterion to its per-tier `coverageVerdict`, giving
|
|
43
|
-
// the AC × test-tier matrix the markdown report (lib/qa/coverage-report.js)
|
|
44
|
-
// renders.
|
|
37
|
+
// Story #5008 removed the `acceptanceMatrix` feeder and the markdown report it
|
|
38
|
+
// fed: the QA workflows read the per-tier verdict and author the missing-test
|
|
39
|
+
// prose directly, so the AC x tier matrix was a round-trip with no reader.
|
|
45
40
|
|
|
46
|
-
/** The three test tiers, in pyramid order (base
|
|
47
|
-
|
|
41
|
+
/** The three test tiers, in pyramid order (base -> top). */
|
|
42
|
+
const TIERS = Object.freeze(['unit', 'contract', 'acceptance']);
|
|
48
43
|
|
|
49
44
|
const PRESENT = 'present';
|
|
50
45
|
const ABSENT = 'absent';
|
|
@@ -217,80 +212,3 @@ export function coverageVerdict(surface = {}) {
|
|
|
217
212
|
|
|
218
213
|
return verdict;
|
|
219
214
|
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Normalize a single criterion descriptor into `{id, label, surface}`. A
|
|
223
|
-
* descriptor may carry `id`, `label` (falls back to id), and either a nested
|
|
224
|
-
* `surface` or a flat `{symbol, tests}` shape.
|
|
225
|
-
*/
|
|
226
|
-
function normalizeOne(entry, index) {
|
|
227
|
-
const e = entry && typeof entry === 'object' ? entry : {};
|
|
228
|
-
const id =
|
|
229
|
-
typeof e.id === 'string' && e.id.trim() !== ''
|
|
230
|
-
? e.id.trim()
|
|
231
|
-
: `AC-${index + 1}`;
|
|
232
|
-
const label =
|
|
233
|
-
typeof e.label === 'string' && e.label.trim() !== '' ? e.label.trim() : id;
|
|
234
|
-
|
|
235
|
-
let surface;
|
|
236
|
-
if (e.surface && typeof e.surface === 'object') {
|
|
237
|
-
surface = e.surface;
|
|
238
|
-
} else if (Array.isArray(e.tests) || typeof e.symbol === 'string') {
|
|
239
|
-
surface = { symbol: e.symbol, tests: e.tests };
|
|
240
|
-
} else {
|
|
241
|
-
surface = {};
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
return { id, label, surface };
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
/**
|
|
248
|
-
* Normalize the criteria input for {@link acceptanceMatrix}. Accepts either an
|
|
249
|
-
* array of criterion descriptors or a plain object keyed by criterion id whose
|
|
250
|
-
* values are surfaces (or `{surface}` wrappers). Returns a normalized array of
|
|
251
|
-
* `{id, label, surface}`.
|
|
252
|
-
*
|
|
253
|
-
* @param {Array<object>|object} criteria
|
|
254
|
-
* @returns {Array<{id:string,label:string,surface:object}>}
|
|
255
|
-
*/
|
|
256
|
-
function normalizeCriteria(criteria) {
|
|
257
|
-
if (Array.isArray(criteria)) {
|
|
258
|
-
return criteria.map((entry, index) => normalizeOne(entry, index));
|
|
259
|
-
}
|
|
260
|
-
if (criteria && typeof criteria === 'object') {
|
|
261
|
-
return Object.entries(criteria).map(([id, value], index) =>
|
|
262
|
-
normalizeOne(
|
|
263
|
-
value && typeof value === 'object' && !Array.isArray(value)
|
|
264
|
-
? { id, ...value }
|
|
265
|
-
: { id, surface: { tests: value } },
|
|
266
|
-
index,
|
|
267
|
-
),
|
|
268
|
-
);
|
|
269
|
-
}
|
|
270
|
-
throw new TypeError(
|
|
271
|
-
'acceptanceMatrix: criteria must be an array or an object',
|
|
272
|
-
);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Build the AC × test-tier matrix: for each acceptance criterion, the per-tier
|
|
277
|
-
* {@link coverageVerdict}. This is the structured shape the markdown report
|
|
278
|
-
* (`lib/qa/coverage-report.js`) renders into a table.
|
|
279
|
-
*
|
|
280
|
-
* @param {Array<{id?:string,label?:string,surface?:object,symbol?:string,tests?:Array}>|Record<string,object>} criteria
|
|
281
|
-
* Acceptance criteria, either as an array of descriptors or an object keyed
|
|
282
|
-
* by criterion id. Each descriptor names a surface (nested `surface`, or a
|
|
283
|
-
* flat `{symbol, tests}`).
|
|
284
|
-
* @returns {{tiers: ReadonlyArray<string>,
|
|
285
|
-
* rows: Array<{id:string,label:string,
|
|
286
|
-
* verdict:ReturnType<typeof coverageVerdict>}>}}
|
|
287
|
-
*/
|
|
288
|
-
export function acceptanceMatrix(criteria) {
|
|
289
|
-
const normalized = normalizeCriteria(criteria);
|
|
290
|
-
const rows = normalized.map(({ id, label, surface }) => ({
|
|
291
|
-
id,
|
|
292
|
-
label,
|
|
293
|
-
verdict: coverageVerdict(surface),
|
|
294
|
-
}));
|
|
295
|
-
return { tiers: TIERS, rows };
|
|
296
|
-
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* detectors/common.js — shared helpers for the signals layer.
|
|
3
3
|
*
|
|
4
4
|
* Hoisted out of the detector modules (retry, rework) plus
|
|
5
|
-
* `signals/read.js
|
|
5
|
+
* the since-deleted `signals/read.js`, and `signals/schema.js`, all of which shipped
|
|
6
6
|
* byte-equivalent copies of these predicates. See Story #2464.
|
|
7
7
|
*/
|
|
8
8
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `lib/signals/` barrel.
|
|
3
3
|
*
|
|
4
|
-
* Consumers do `import {
|
|
4
|
+
* Consumers do `import { schema, appendSignal } from './lib/signals/index.js'`
|
|
5
5
|
* (or `import * as signals from './lib/signals/index.js'`) so a future
|
|
6
6
|
* shape migration only has to touch this file.
|
|
7
7
|
*
|
|
@@ -9,18 +9,20 @@
|
|
|
9
9
|
* - Epic #1181 / Story #1438 / Task #1459 — initial barrel with `read`
|
|
10
10
|
* + `schema`; `buildSpanTree` was a throwing placeholder.
|
|
11
11
|
* - Epic #1181 / Story #1440 / Task #1461 — placeholder replaced by
|
|
12
|
-
* the real
|
|
12
|
+
* the real span-tree builder.
|
|
13
13
|
* - Story #1476 — `appendSignal` / `appendTrace` re-exported here
|
|
14
14
|
* via `./write.js` so the gate scripts (and any
|
|
15
15
|
* new code) converge on `lib/signals/` instead of importing the
|
|
16
16
|
* writer directly from `lib/observability/`.
|
|
17
|
+
* - Story #5003 — the reader half (`read`, `buildSpanTree`) went with the
|
|
18
|
+
* debug viewer that consumed it: it walked a `run-<id>/` layout no v2
|
|
19
|
+
* writer populates. `appendTrace` went with the trace hook, its only
|
|
20
|
+
* producer. What remains is the live write surface.
|
|
17
21
|
*
|
|
18
22
|
* @module lib/signals
|
|
19
23
|
*/
|
|
20
24
|
|
|
21
|
-
import { read } from './read.js';
|
|
22
25
|
import * as schema from './schema.js';
|
|
23
|
-
import {
|
|
24
|
-
import { appendSignal, appendTrace, forEachLine } from './write.js';
|
|
26
|
+
import { appendSignal, forEachLine } from './write.js';
|
|
25
27
|
|
|
26
|
-
export { appendSignal,
|
|
28
|
+
export { appendSignal, forEachLine, schema };
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
* Signals schema — single source of truth for event-kind constants and
|
|
3
3
|
* shape guards (Epic #1181 / Story #1438 / Task #1458).
|
|
4
4
|
*
|
|
5
|
-
* Both writers (`lib/observability/signals-writer.js` callers) and
|
|
6
|
-
*
|
|
7
|
-
* import their field names from this module so the
|
|
8
|
-
* stays under one schema.
|
|
5
|
+
* Both writers (`lib/observability/signals-writer.js` callers) and readers
|
|
6
|
+
* (its `forEachLine` / `forEachSignalStreamLine` walkers, and the retro's
|
|
7
|
+
* gather-signals phase) import their field names from this module so the
|
|
8
|
+
* on-disk NDJSON shape stays under one schema.
|
|
9
9
|
*
|
|
10
10
|
* Pure module: importing has **no I/O side effects**. The exported
|
|
11
11
|
* `EVENT_KINDS` object is `Object.freeze`'d so consumers can use it as a
|
|
@@ -14,30 +14,25 @@
|
|
|
14
14
|
* ## Event-kind enumeration
|
|
15
15
|
*
|
|
16
16
|
* The set below is the audited union of `kind:` literals emitted via
|
|
17
|
-
* `signals-writer.appendSignal`
|
|
18
|
-
*
|
|
17
|
+
* `signals-writer.appendSignal` across the codebase as of Epic #1181
|
|
18
|
+
* (audit-snapshot 2026-05-11):
|
|
19
19
|
*
|
|
20
20
|
* Signals-writer `appendSignal` call sites:
|
|
21
21
|
* - `friction` — quality-gate / runtime friction (diagnose-friction.js,
|
|
22
22
|
* lib/gates/friction.js)
|
|
23
23
|
* - `acceptance-eval` — acceptance-eval.js per-criterion terminus signal.
|
|
24
|
-
* - `wave-start` / `wave-complete` — wave-window anchors
|
|
25
|
-
*
|
|
26
|
-
* - `wave-end` — span-tree pairing anchor (retained for span-tree)
|
|
24
|
+
* - `wave-start` / `wave-complete` — wave-window anchors.
|
|
25
|
+
* - `wave-end` — wave-window pairing anchor.
|
|
27
26
|
* - `state-transition` — notification-derived window anchor.
|
|
28
27
|
*
|
|
29
28
|
* The `dispatched` kind was deleted in the Epic #4406 signal-contract
|
|
30
29
|
* cutover — it had no live emitter and no consumer.
|
|
31
30
|
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* emitted by `lib/signals/detectors/*`; `hotspot`, `churn`, `idle` remain
|
|
38
|
-
* pinned in the enum for the aggregator's kind-count rollup even though no
|
|
39
|
-
* live detector emits them):
|
|
40
|
-
* - `hotspot`, `rework`, `churn`, `idle`, `retry`
|
|
31
|
+
* Producerless kinds, pinned in the enum so a re-introduction needs no schema
|
|
32
|
+
* bump. Story #5003 deleted the last emitters of `trace` (the tool-trace hook
|
|
33
|
+
* and its `appendTrace` writer limb) and of `rework` / `retry` (the detector
|
|
34
|
+
* pair the hook fed); `hotspot`, `churn`, `idle` never had one:
|
|
35
|
+
* - `trace`, `hotspot`, `rework`, `churn`, `idle`, `retry`
|
|
41
36
|
*
|
|
42
37
|
* ## Common envelope (canonical — Epic #4406 / Story #4413)
|
|
43
38
|
*
|
|
@@ -68,18 +63,18 @@ import { isPositiveInt } from './detectors/common.js';
|
|
|
68
63
|
|
|
69
64
|
/**
|
|
70
65
|
* Frozen enumeration of every event kind currently emitted by
|
|
71
|
-
* `signals-writer.appendSignal
|
|
72
|
-
*
|
|
66
|
+
* `signals-writer.appendSignal`, plus the producerless kinds a future Story
|
|
67
|
+
* may re-introduce an emitter for.
|
|
73
68
|
*
|
|
74
69
|
* Field names are kebab-cased to match the on-disk literals.
|
|
75
70
|
*/
|
|
76
71
|
export const EVENT_KINDS = Object.freeze({
|
|
77
72
|
FRICTION: 'friction',
|
|
78
73
|
TRACE: 'trace',
|
|
79
|
-
// Wave-window forensics signals
|
|
80
|
-
//
|
|
81
|
-
//
|
|
82
|
-
//
|
|
74
|
+
// Wave-window forensics signals. Story #4545 deleted the `waveParallelism`
|
|
75
|
+
// consumer (perf-aggregator) with the execution-analysis surface, and
|
|
76
|
+
// Story #5003 deleted the span-tree that paired them; the kinds stay
|
|
77
|
+
// pinned so a re-introduced window reader needs no schema bump.
|
|
83
78
|
WAVE_START: 'wave-start',
|
|
84
79
|
WAVE_END: 'wave-end',
|
|
85
80
|
WAVE_COMPLETE: 'wave-complete',
|
|
@@ -156,7 +151,7 @@ function isTimestamp(v) {
|
|
|
156
151
|
* recognised `kind`. Canonical keys only — the legacy `timestamp` / `epic`
|
|
157
152
|
* aliases were deleted in the Epic #4406 cutover.
|
|
158
153
|
*
|
|
159
|
-
* Returns true when the envelope is well-formed. Used by
|
|
154
|
+
* Returns true when the envelope is well-formed. Used by the stream readers
|
|
160
155
|
* to discard malformed lines before yielding them to the consumer.
|
|
161
156
|
*
|
|
162
157
|
* @param {unknown} evt
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `lib/signals/write.js` — thin re-export of the signals
|
|
2
|
+
* `lib/signals/write.js` — thin re-export of the signals writer.
|
|
3
3
|
*
|
|
4
4
|
* The real implementation lives at `../observability/signals-writer.js`
|
|
5
5
|
* (Epic #1030 / Story #1041). This module exists so callers can converge
|
|
6
|
-
* on `lib/signals/` for
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* from
|
|
10
|
-
*
|
|
11
|
-
*
|
|
6
|
+
* on `lib/signals/` for the write surface. New code should
|
|
7
|
+
* `import { appendSignal } from './lib/signals/index.js'` (or
|
|
8
|
+
* `'./lib/signals/write.js'` for a narrower import); legacy direct imports
|
|
9
|
+
* from `lib/observability/` keep working unchanged.
|
|
10
|
+
*
|
|
11
|
+
* `appendTrace` was removed in Story #5003 together with the tool-trace
|
|
12
|
+
* hook — its only producer — and the viewer that was its only reader.
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
export {
|
|
15
16
|
appendSignal,
|
|
16
|
-
appendTrace,
|
|
17
17
|
forEachLine,
|
|
18
18
|
} from '../observability/signals-writer.js';
|