@event4u/agent-config 14.7.0 → 14.9.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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +175 -390
- package/README.md +1 -1
- package/agents/templates/.ai-council.yml.example +34 -4
- package/dist/agent-src/commands/evals/git-pr-merge.json +13 -0
- package/dist/agent-src/commands/evals/roadmap.json +17 -1
- package/dist/agent-src/commands/pr/create.md +14 -2
- package/dist/agent-src/commands/pr/merge.md +383 -0
- package/dist/agent-src/commands/review/changes.md +95 -14
- package/dist/agent-src/commands/roadmap/process-full.md +157 -3
- package/dist/agent-src/commands/roadmap.md +1 -1
- package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +46 -36
- package/dist/agent-src/contexts/execution/autonomy-mechanics.md +37 -2
- package/dist/agent-src/contexts/execution/host-capability-manifest.md +77 -0
- package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +100 -2
- package/dist/agent-src/contexts/execution/roadmap-process-loop.md +154 -2
- package/dist/agent-src/contexts/execution/subagent-response-contract.md +80 -0
- package/dist/agent-src/rules/artifact-drafting-protocol.md +5 -1
- package/dist/agent-src/rules/decision-revisit-gate.md +65 -33
- package/dist/agent-src/rules/recurring-criticism.md +1 -1
- package/dist/agent-src/rules/roadmap-progress-sync.md +19 -0
- package/dist/agent-src/rules/source-confidentiality.md +1 -1
- package/dist/agent-src/rules/untrusted-input-defense.md +9 -3
- package/dist/agent-src/scripts/archive_completed_roadmaps.ts +7 -4
- package/dist/agent-src/scripts/dashboard_mode.ts +212 -0
- package/dist/agent-src/scripts/update_roadmap_progress.ts +47 -48
- package/dist/agent-src/skills/adr-create/SKILL.md +124 -5
- package/dist/agent-src/skills/code-review/evals/evals.json +87 -46
- package/dist/agent-src/skills/decision-record/SKILL.md +61 -3
- package/dist/agent-src/skills/decision-review/SKILL.md +65 -0
- package/dist/agent-src/skills/humanizer/SKILL.md +39 -0
- package/dist/agent-src/skills/humanizer/evals/strip_fixtures.json +57 -0
- package/dist/agent-src/skills/humanizer/references/fixtures.md +54 -0
- package/dist/agent-src/skills/judge-spec-compliance/SKILL.md +154 -0
- package/dist/agent-src/skills/judge-synthesis/SKILL.md +45 -0
- package/dist/agent-src/skills/merge-conflicts/SKILL.md +26 -0
- package/dist/agent-src/skills/roadmap-writing/SKILL.md +18 -18
- package/dist/agent-src/skills/security/SKILL.md +8 -0
- package/dist/agent-src/skills/security-audit/SKILL.md +12 -1
- package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
- package/dist/agent-src/templates/roadmaps.md +28 -2
- package/dist/cli/registry.js +3 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli-delegate/{chunk-FBKL6JWT.js → chunk-77GR3VD4.js} +68 -43
- package/dist/cli-delegate/{chunk-JZ4NR2TW.js → chunk-7PRE6ZV2.js} +1 -1
- package/dist/cli-delegate/{chunk-UEZ7D35A.js → chunk-CYH5SP6M.js} +4 -23
- package/dist/cli-delegate/{chunk-Q26HT4QT.js → chunk-E46KPN6K.js} +251 -150
- package/dist/cli-delegate/{chunk-74E3TKWV.js → chunk-H4VIVD4C.js} +5 -5
- package/dist/cli-delegate/chunk-I3EIN2YG.js +36 -0
- package/dist/cli-delegate/{chunk-4VR4ORQ6.js → chunk-LPPWO5CE.js} +4 -3
- package/dist/cli-delegate/{chunk-7F3VYSM2.js → chunk-PLSG6UL5.js} +14 -14
- package/dist/cli-delegate/cmd_adr_effective.js +1162 -0
- package/dist/cli-delegate/cmd_conformance.js +101 -25
- package/dist/cli-delegate/cmd_converge.js +3 -3
- package/dist/cli-delegate/cmd_doctor.js +7 -7
- package/dist/cli-delegate/cmd_export.js +6 -6
- package/dist/cli-delegate/cmd_handoff.js +7 -6
- package/dist/cli-delegate/cmd_memory_get.js +2 -1
- package/dist/cli-delegate/cmd_migrate.js +2 -2
- package/dist/cli-delegate/cmd_preflight.js +5 -5
- package/dist/cli-delegate/cmd_prune.js +6 -6
- package/dist/cli-delegate/cmd_route_audit.js +6 -5
- package/dist/cli-delegate/cmd_route_explain.js +3 -3
- package/dist/cli-delegate/cmd_session_recycle.js +3 -3
- package/dist/cli-delegate/cmd_settings_get.js +4 -4
- package/dist/cli-delegate/cmd_settings_migrate.js +6 -6
- package/dist/cli-delegate/cmd_settings_set.js +1 -1
- package/dist/cli-delegate/cmd_sync.js +6 -6
- package/dist/cli-delegate/cmd_uninstall.js +6 -6
- package/dist/cli-delegate/cmd_update.js +3 -3
- package/dist/cli-delegate/cmd_upgrade.js +3 -3
- package/dist/cli-delegate/cmd_validate.js +6 -6
- package/dist/cli-delegate/cmd_versions.js +3 -3
- package/dist/discovery/deprecation-report.md +1 -1
- package/dist/discovery/discovery-manifest.json +83 -30
- package/dist/discovery/discovery-manifest.json.sha256 +1 -1
- package/dist/discovery/discovery-manifest.summary.md +4 -4
- package/dist/discovery/dormancy-report.md +1 -1
- package/dist/discovery/orphan-report.md +1 -1
- package/dist/discovery/packs.json +11 -9
- package/dist/discovery/trust-report.md +2 -2
- package/dist/discovery/workspaces.json +9 -7
- package/dist/hooks/dispatch.js +1295 -812
- package/dist/install/globalRuleLayers.js +169 -0
- package/dist/install/globalRuleLayers.js.map +1 -0
- package/dist/install/partitionEligibility.js +156 -0
- package/dist/install/partitionEligibility.js.map +1 -1
- package/dist/install/ruleLayerPartition.js +157 -0
- package/dist/install/ruleLayerPartition.js.map +1 -0
- package/dist/mcp/registry-manifest.json +3 -3
- package/dist/mcp/server.json +2 -2
- package/dist/mcp/server.mjs +1358 -805
- package/dist/scripts/_lib/claude_plugin.js +162 -0
- package/dist/scripts/_lib/claude_plugin.js.map +1 -0
- package/dist/scripts/_lib/environment_detector.js +397 -0
- package/dist/scripts/_lib/environment_detector.js.map +1 -0
- package/dist/scripts/_lib/prune_empty_dirs.js +85 -0
- package/dist/scripts/_lib/prune_empty_dirs.js.map +1 -0
- package/dist/scripts/_lib/spawn_env.js +129 -0
- package/dist/scripts/_lib/spawn_env.js.map +1 -0
- package/dist/scripts/ai_council/modes.js +199 -0
- package/dist/scripts/ai_council/modes.js.map +1 -0
- package/dist/scripts/ai_council/transport_resolver.js +418 -0
- package/dist/scripts/ai_council/transport_resolver.js.map +1 -0
- package/dist/scripts/condense.js +52 -89
- package/dist/scripts/condense.js.map +1 -1
- package/dist/server/routes/wizard.js +3 -2
- package/dist/server/routes/wizard.js.map +1 -1
- package/dist/ui/assets/index-Cxgy63kz.js +26 -0
- package/dist/ui/assets/index-Cxgy63kz.js.map +1 -0
- package/dist/ui/index.html +1 -1
- package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +45 -1
- package/docs/guidelines/agent-infra/false-green.md +47 -1
- package/docs/guidelines/agent-infra/traceability-field-mechanics.md +50 -0
- package/docs/guidelines/agent-infra/untrusted-input-spotlighting.md +17 -0
- package/package.json +7 -3
- package/src/agent-src/scripts/archive_completed_roadmaps.ts +7 -4
- package/src/agent-src/scripts/dashboard_mode.ts +212 -0
- package/src/agent-src/scripts/update_roadmap_progress.ts +47 -48
- package/src/config/ci-local-parity.yml +21 -0
- package/src/config/estate-count-budget.json +13 -471
- package/src/config/evaluator-budgets.json +4 -4
- package/src/config/gate-coverage.yml +458 -12
- package/src/config/gate-violation-baselines.json +18 -8
- package/src/config/gitignore-block.txt +15 -2
- package/src/config/hook-latency-budget.json +5 -0
- package/src/config/publish-surface.json +60 -0
- package/src/config/requirements-trace-budget.json +32 -0
- package/src/config/rule-stub-ceilings.json +25 -4
- package/src/install/globalRuleLayers.ts +197 -0
- package/src/install/partitionEligibility.ts +177 -0
- package/src/install/ruleLayerPartition.ts +212 -0
- package/src/scripts/_cli/cmd_adr_effective.ts +484 -0
- package/src/scripts/_dispatch.bash +18 -0
- package/src/scripts/_lib/adr_frontmatter.test.ts +365 -0
- package/src/scripts/_lib/adr_frontmatter.ts +459 -0
- package/src/scripts/_lib/base_tree.ts +175 -0
- package/src/scripts/_lib/billing_grant.ts +165 -0
- package/src/scripts/_lib/billing_grant_cli.ts +123 -0
- package/src/scripts/_lib/council_fallback_posture.ts +53 -6
- package/src/scripts/_lib/council_fallback_wiring.ts +61 -1
- package/src/scripts/_lib/envelope_grounding.ts +11 -1
- package/src/scripts/_lib/host_capability.ts +59 -5
- package/src/scripts/_lib/layer_overlap_notice.ts +11 -2
- package/src/scripts/_lib/prune_empty_dirs.ts +80 -0
- package/src/scripts/_lib/quota_parked.ts +133 -0
- package/src/scripts/_lib/retrieval_sanitize.ts +62 -0
- package/src/scripts/_lib/review_telemetry.ts +196 -0
- package/src/scripts/_lib/subagent_response.ts +92 -0
- package/src/scripts/adr/evidence_census.ts +899 -0
- package/src/scripts/adr/regenerate_index.ts +25 -38
- package/src/scripts/adr_cite_check.ts +540 -39
- package/src/scripts/ai_council/clients.ts +12 -1
- package/src/scripts/ai_council/config.ts +72 -115
- package/src/scripts/ai_council/fallback_config.ts +19 -7
- package/src/scripts/ai_council/mid_flight_fallback.ts +88 -7
- package/src/scripts/ai_council/orchestrator.ts +2 -2
- package/src/scripts/ai_council/py_format.ts +124 -0
- package/src/scripts/ai_council/transport_resolver.ts +65 -2
- package/src/scripts/audit_adr_coverage.ts +134 -21
- package/src/scripts/bench_hook_latency.ts +204 -0
- package/src/scripts/build_archive_index.ts +34 -0
- package/src/scripts/check_adr_frontmatter.ts +574 -39
- package/src/scripts/check_council_pin_staleness.ts +300 -0
- package/src/scripts/check_estate_count.ts +420 -293
- package/src/scripts/check_gate_coverage.ts +91 -0
- package/src/scripts/check_hook_bundle_content.ts +219 -0
- package/src/scripts/check_new_adr_evidence.ts +529 -0
- package/src/scripts/check_no_stub_inventory_table.ts +292 -0
- package/src/scripts/check_pack_size.ts +234 -1
- package/src/scripts/check_publish_surface.ts +297 -0
- package/src/scripts/check_references.ts +18 -0
- package/src/scripts/check_requirements_trace.ts +378 -0
- package/src/scripts/check_rule_layer_partition.ts +531 -0
- package/src/scripts/check_secret_leak.ts +166 -12
- package/src/scripts/check_single_delivery.ts +137 -4
- package/src/scripts/check_standing_rule_delivery.ts +8 -2
- package/src/scripts/code_graph/cli.ts +44 -5
- package/src/scripts/code_graph/extract.ts +87 -0
- package/src/scripts/condense.ts +61 -91
- package/src/scripts/council_cli.ts +12 -16
- package/src/scripts/detect_ai_tells.ts +87 -0
- package/src/scripts/dispatch_r2_reviewer.ts +42 -0
- package/src/scripts/external_sources_denylist.json +4 -1
- package/src/scripts/generate_capabilities_index.ts +41 -0
- package/src/scripts/git_authorization_hook.ts +54 -4
- package/src/scripts/hooks/block_unauthorized_git.ts +41 -3
- package/src/scripts/hooks/dispatch_hook.ts +154 -187
- package/src/scripts/hooks/dispatch_issues.ts +38 -19
- package/src/scripts/hooks/fallback_yaml.ts +66 -0
- package/src/scripts/hooks/host_semantics.ts +21 -0
- package/src/scripts/hooks/injection_budget.ts +13 -3
- package/src/scripts/hooks/py_json_dumps.ts +103 -0
- package/src/scripts/hooks/run_continuation_hook.ts +3 -1
- package/src/scripts/hooks/state_io.ts +88 -1
- package/src/scripts/hooks/stdin_failure_policy.ts +96 -0
- package/src/scripts/hooks/subagent_ledger_hook.ts +76 -11
- package/src/scripts/injection_scan_hook.ts +257 -15
- package/src/scripts/lint_adr_sweep_routing.ts +365 -0
- package/src/scripts/lint_hook_manifest.ts +49 -0
- package/src/scripts/lint_provenance_vocabulary.ts +472 -4
- package/src/scripts/lint_workflow_security.ts +53 -10
- package/src/scripts/lint_workflow_security_allowlist.json +2 -18
- package/src/scripts/report_envelope_rate.ts +166 -0
- package/src/scripts/review_axis_report.ts +218 -0
- package/src/scripts/routing_doctor.ts +5 -1
- package/src/scripts/run_supervise.ts +46 -1
- package/src/scripts/schemas/evals.schema.json +5 -0
- package/src/scripts/sync_pr_branch.ts +170 -20
- package/dist/cli/commands/commands.candidates.test.js +0 -257
- package/dist/cli/commands/commands.candidates.test.js.map +0 -1
- package/dist/cli/commands/profiles.test.js +0 -88
- package/dist/cli/commands/profiles.test.js.map +0 -1
- package/dist/cli/commands/recordTriggerEval.test.js +0 -113
- package/dist/cli/commands/recordTriggerEval.test.js.map +0 -1
- package/dist/cli/configRoot.test.js +0 -97
- package/dist/cli/configRoot.test.js.map +0 -1
- package/dist/cli/mcp/content.test.js +0 -54
- package/dist/cli/mcp/content.test.js.map +0 -1
- package/dist/cli/mcp/dispatch.test.js +0 -108
- package/dist/cli/mcp/dispatch.test.js.map +0 -1
- package/dist/server/writeRoot.test.js +0 -91
- package/dist/server/writeRoot.test.js.map +0 -1
- package/dist/shared/capabilities.test.js +0 -39
- package/dist/shared/capabilities.test.js.map +0 -1
- package/dist/ui/assets/index-C1pBRm1f.js +0 -26
- package/dist/ui/assets/index-C1pBRm1f.js.map +0 -1
- package/dist/cli-delegate/{chunk-PPQO4NGR.js → chunk-6RJA2F5A.js} +3 -3
- package/dist/cli-delegate/{chunk-6EOCNQAM.js → chunk-E4XIZDIB.js} +0 -0
- package/dist/cli-delegate/{chunk-GJ5BVHXM.js → chunk-PMEKGDED.js} +3 -3
|
@@ -21,6 +21,11 @@
|
|
|
21
21
|
* do not hand-merge) versus authored (a human decision). Auto-resolving a
|
|
22
22
|
* content conflict is how a parallel session's work disappears.
|
|
23
23
|
*
|
|
24
|
+
* Classification changes the ADVICE, not the conflict. A path stays a hotspot by
|
|
25
|
+
* frequency while becoming mechanical to resolve, so a class added here is never
|
|
26
|
+
* conflict-count reduction and must not be banked as drawdown (AI council
|
|
27
|
+
* 2026-08-21, both seats; roadmap road-to-merge-hotspot-drawdown).
|
|
28
|
+
*
|
|
24
29
|
* Exit codes: 0 = already current, or merged cleanly · 1 = conflict, or the base
|
|
25
30
|
* could not be resolved · 2 = internal error. `scanned:` on every path.
|
|
26
31
|
*/
|
|
@@ -35,10 +40,32 @@ const NETWORK_TIMEOUT_MS = 8_000;
|
|
|
35
40
|
|
|
36
41
|
/** Paths that are GENERATED — a conflict here is regenerated, never hand-merged. */
|
|
37
42
|
const GENERATED = [
|
|
43
|
+
// Untracked in THIS repository since 2026-08-21 (it was the #1 conflict
|
|
44
|
+
// path: 830 commits/60d, in the conflict set of every open CONFLICTING PR).
|
|
45
|
+
// The entry STAYS anyway, and the retirement criterion is a declared window
|
|
46
|
+
// rather than "one release" — the AI council flagged the release count as
|
|
47
|
+
// arbitrary and unverifiable. Remove this entry once no open branch predates
|
|
48
|
+
// the untrack commit, which is checkable:
|
|
49
|
+
//
|
|
50
|
+
// git branch -r --contains <untrack-commit> # must list every open branch
|
|
51
|
+
//
|
|
52
|
+
// Until then a straggler branch created before the untrack still carries the
|
|
53
|
+
// tracked file, and a conflict on it is still resolved by regeneration.
|
|
38
54
|
'agents/roadmaps-progress.md',
|
|
39
55
|
'agents/index.md',
|
|
40
56
|
'docs/catalog.md',
|
|
41
57
|
'dist/agent-src/',
|
|
58
|
+
// Written by `src/scripts/adr/regenerate_index.ts`, which takes the decisions
|
|
59
|
+
// directory as an ARGUMENT — so the path literal appears nowhere in the
|
|
60
|
+
// generator and every grep-based audit of this list missed it. Found instead
|
|
61
|
+
// by measurement: 4 of the last 50 sessions resolved a conflict here, and
|
|
62
|
+
// its only correct resolution is `task regenerate-adr-index`, never a hunk
|
|
63
|
+
// merge of two append-shaped indexes.
|
|
64
|
+
'docs/decisions/INDEX.md',
|
|
65
|
+
// Compiled by `compile_router.ts`. The `dist/agent-src/` prefix above does
|
|
66
|
+
// NOT match a sibling one level up under `dist/`, so this file was routed to
|
|
67
|
+
// a human decision despite being pure build output.
|
|
68
|
+
'dist/router.json',
|
|
42
69
|
'.augment/',
|
|
43
70
|
// Compiled from `hook_manifest.yaml` by `task build-ts`, never hand-written.
|
|
44
71
|
// It was classified AUTHORED until 2026-08-20, so this tool told the reader
|
|
@@ -47,8 +74,53 @@ const GENERATED = [
|
|
|
47
74
|
// times and named it structural: main adds a concern and recompiles, so
|
|
48
75
|
// every open branch collides here. Regenerate; never merge.
|
|
49
76
|
'src/scripts/hook_manifest.json',
|
|
77
|
+
// Written together by one `build_archive_index.ts` call (`:409-410`) from the
|
|
78
|
+
// archived roadmap tree, so neither is ever hand-authored. They were
|
|
79
|
+
// classified AUTHORED until 2026-08-21, which made this tool ask for a human
|
|
80
|
+
// decision about a file whose only correct resolution is regeneration --
|
|
81
|
+
// the identical defect the hook_manifest.json comment above records, on two
|
|
82
|
+
// more paths at 47 commits/60d each. They conflict in 2 of the 7 open PRs
|
|
83
|
+
// measured for road-to-merge-hotspot-drawdown. Regenerate; never merge.
|
|
84
|
+
'agents/roadmaps/archive/INDEX.md',
|
|
85
|
+
'agents/roadmaps/archive/index.json',
|
|
50
86
|
];
|
|
51
87
|
|
|
88
|
+
/**
|
|
89
|
+
* Paths that are MEASURED BASELINES -- a conflict here is neither regenerated
|
|
90
|
+
* nor hand-merged. It is RE-MEASURED on the merged tree, and the number that
|
|
91
|
+
* measurement produces is the resolution.
|
|
92
|
+
*
|
|
93
|
+
* Why this is a third class and not a variant of GENERATED: a generated file has
|
|
94
|
+
* one correct content given the tree, so "regenerate" is a complete instruction.
|
|
95
|
+
* A ratchet baseline records what a tree MEASURED at a point in time, and two
|
|
96
|
+
* branches legitimately measured two different trees -- so there is no side to
|
|
97
|
+
* take and no file to re-render. Picking a side on a ratchet number is how the
|
|
98
|
+
* ratchet silently loosens, and mixing hunks yields a baseline matching neither
|
|
99
|
+
* branch.
|
|
100
|
+
*
|
|
101
|
+
* Why this tool never performs the re-measurement itself (AI council 2026-08-21,
|
|
102
|
+
* both seats): "re-measure instead of merge" delegates conflict resolution to a
|
|
103
|
+
* script and its execution environment, and a wrong or environment-dependent
|
|
104
|
+
* measurement would overwrite a deliberate tightening with nothing objecting,
|
|
105
|
+
* because the result looks measured either way. So this class NAMES the
|
|
106
|
+
* resolution and stops. The human runs it, with the result in front of them.
|
|
107
|
+
*
|
|
108
|
+
* `gate-violation-baselines.json` conflicted in 7 of the 7 open PRs measured for
|
|
109
|
+
* road-to-merge-hotspot-drawdown, and it is not gitignorable: its counts are not
|
|
110
|
+
* a function of the tree, so the committed number is the only "before" side that
|
|
111
|
+
* exists.
|
|
112
|
+
*
|
|
113
|
+
* `estate-count-budget.json` USED to be the other member and is deliberately not
|
|
114
|
+
* listed any more (ADR-243). Its metrics ARE a function of the tree, so
|
|
115
|
+
* `check_estate_count` measures the floor at the base ref instead of storing it,
|
|
116
|
+
* and the file now carries policy only. A conflict in it is an ordinary AUTHORED
|
|
117
|
+
* one — two humans editing the same policy sentence — and telling the reader to
|
|
118
|
+
* "re-run the measurement" for that would name a resolution the file no longer
|
|
119
|
+
* has. Removing the row is the point of the change, not an oversight: the row
|
|
120
|
+
* described a conflict that no longer occurs.
|
|
121
|
+
*/
|
|
122
|
+
const REMEASURED = ['src/config/gate-violation-baselines.json'];
|
|
123
|
+
|
|
52
124
|
function sh(cmd: string, args: readonly string[], cwd: string): { ok: boolean; out: string; err: string } {
|
|
53
125
|
const r = spawnSync(cmd, [...args], {
|
|
54
126
|
cwd,
|
|
@@ -60,17 +132,59 @@ function sh(cmd: string, args: readonly string[], cwd: string): { ok: boolean; o
|
|
|
60
132
|
}
|
|
61
133
|
|
|
62
134
|
/** True when `rel` is a generated artefact rather than an authored one. */
|
|
135
|
+
/**
|
|
136
|
+
* The subset of GENERATED that this repository no longer commits at all
|
|
137
|
+
* (`road-to-generated-artifacts-out-of-index`, 2026-08-22). They are still
|
|
138
|
+
* generated, so they stay in `GENERATED` and keep being reported — a straggler
|
|
139
|
+
* branch created before the untrack still carries them, which is exactly when
|
|
140
|
+
* the reader needs to be told something.
|
|
141
|
+
*
|
|
142
|
+
* What changes is the INSTRUCTION. A branch that predates the cutover hits a
|
|
143
|
+
* `modify/delete` conflict here, not a content conflict, and `git checkout
|
|
144
|
+
* --ours` has no side to check out: the correct resolution is to take the
|
|
145
|
+
* deletion. Printing the generic advice would send the reader to re-add the
|
|
146
|
+
* file, which is precisely how PR #1505 put the dashboard back on `main` a day
|
|
147
|
+
* after it was first untracked.
|
|
148
|
+
*/
|
|
149
|
+
const UNTRACKED_BY_DESIGN: readonly string[] = [
|
|
150
|
+
'agents/roadmaps-progress.md',
|
|
151
|
+
'agents/roadmaps/archive/INDEX.md',
|
|
152
|
+
'agents/roadmaps/archive/index.json',
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
/** Is this a generated path this repository deliberately does not commit? */
|
|
156
|
+
export function isUntrackedByDesign(rel: string): boolean {
|
|
157
|
+
return UNTRACKED_BY_DESIGN.includes(rel);
|
|
158
|
+
}
|
|
159
|
+
|
|
63
160
|
export function isGenerated(rel: string): boolean {
|
|
64
161
|
const norm = rel.replace(/\\/g, '/');
|
|
65
162
|
return GENERATED.some((g) => (g.endsWith('/') ? norm.startsWith(g) : norm === g));
|
|
66
163
|
}
|
|
67
164
|
|
|
165
|
+
/**
|
|
166
|
+
* True when `rel` is listed as a measured ratchet baseline.
|
|
167
|
+
*
|
|
168
|
+
* This does NOT assert exclusivity against `GENERATED` — it only reads its own
|
|
169
|
+
* array. `classifyConflicts` establishes the precedence (generated first), so a
|
|
170
|
+
* path added to both arrays would route as generated while this predicate also
|
|
171
|
+
* returned true, and no test would catch it. Keep the arrays disjoint; the
|
|
172
|
+
* per-path exclusivity assertions in the test file cover today's two members
|
|
173
|
+
* only.
|
|
174
|
+
*/
|
|
175
|
+
export function isRemeasured(rel: string): boolean {
|
|
176
|
+
const norm = rel.replace(/\\/g, '/');
|
|
177
|
+
return REMEASURED.some((g) => (g.endsWith('/') ? norm.startsWith(g) : norm === g));
|
|
178
|
+
}
|
|
179
|
+
|
|
68
180
|
export interface Plan {
|
|
69
181
|
/** 0 = nothing to do or merged · 1 = needs a human · 2 = internal. */
|
|
70
182
|
exit: 0 | 1 | 2;
|
|
71
183
|
message: string;
|
|
72
184
|
/** Conflicted paths, split so the caller knows which to regenerate. */
|
|
73
185
|
generated: string[];
|
|
186
|
+
/** Conflicted measured baselines — re-measure on the merged tree, never merge. */
|
|
187
|
+
remeasured: string[];
|
|
74
188
|
authored: string[];
|
|
75
189
|
scanned: number;
|
|
76
190
|
}
|
|
@@ -82,14 +196,57 @@ export interface Plan {
|
|
|
82
196
|
* the split is the useful part: a generated conflict has one correct resolution
|
|
83
197
|
* (regenerate) and an authored one has none that a script may choose.
|
|
84
198
|
*/
|
|
85
|
-
export function classifyConflicts(files: readonly string[]): Pick<Plan, 'generated' | 'authored'> {
|
|
199
|
+
export function classifyConflicts(files: readonly string[]): Pick<Plan, 'generated' | 'remeasured' | 'authored'> {
|
|
86
200
|
const generated: string[] = [];
|
|
201
|
+
const remeasured: string[] = [];
|
|
87
202
|
const authored: string[] = [];
|
|
88
203
|
for (const f of files) {
|
|
89
|
-
|
|
90
|
-
(
|
|
204
|
+
const rel = f.trim();
|
|
205
|
+
if (rel === '') continue;
|
|
206
|
+
if (isGenerated(rel)) generated.push(rel);
|
|
207
|
+
else if (isRemeasured(rel)) remeasured.push(rel);
|
|
208
|
+
else authored.push(rel);
|
|
91
209
|
}
|
|
92
|
-
return { generated, authored };
|
|
210
|
+
return { generated, remeasured, authored };
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Render the conflict report for a plan that needs a human.
|
|
215
|
+
*
|
|
216
|
+
* Pure and exported so the WORDING is testable without producing a real merge
|
|
217
|
+
* conflict. That matters more than it looks: the per-class instruction is the
|
|
218
|
+
* entire value of the classification, and while this lived inline in `main()`
|
|
219
|
+
* the whole block could be deleted and every test stayed green — the header
|
|
220
|
+
* still counted the conflict, and the paths went unnamed with no instruction.
|
|
221
|
+
*/
|
|
222
|
+
export function renderConflictReport(plan: Plan): string {
|
|
223
|
+
const out: string[] = [`❌ ${plan.message}\n`];
|
|
224
|
+
const untracked = plan.generated.filter(isUntrackedByDesign);
|
|
225
|
+
const regenerable = plan.generated.filter((f) => !isUntrackedByDesign(f));
|
|
226
|
+
if (regenerable.length > 0) {
|
|
227
|
+
out.push(`\n GENERATED (${String(regenerable.length)}) — resolve by REGENERATING, never by mixing hunks:\n`);
|
|
228
|
+
for (const f of regenerable) out.push(` · ${f}\n`);
|
|
229
|
+
out.push(' → git checkout --ours <file> && task sync && task generate-tools\n');
|
|
230
|
+
}
|
|
231
|
+
if (untracked.length > 0) {
|
|
232
|
+
out.push(
|
|
233
|
+
`\n UNTRACKED BY DESIGN (${String(untracked.length)}) — this repository does not commit these; TAKE THE DELETION:\n`,
|
|
234
|
+
);
|
|
235
|
+
for (const f of untracked) out.push(` · ${f}\n`);
|
|
236
|
+
out.push(' → git rm --cached -- <file> (the working-tree copy stays; regenerate it locally)\n');
|
|
237
|
+
}
|
|
238
|
+
if (plan.remeasured.length > 0) {
|
|
239
|
+
out.push(
|
|
240
|
+
`\n REMEASURED (${String(plan.remeasured.length)}) — RE-RUN THE MEASUREMENT on the merged tree; never merge, never pick a side:\n`,
|
|
241
|
+
);
|
|
242
|
+
for (const f of plan.remeasured) out.push(` · ${f}\n`);
|
|
243
|
+
out.push(' → resolve the tree, then re-run the gate that owns the baseline and record its number\n');
|
|
244
|
+
}
|
|
245
|
+
if (plan.authored.length > 0) {
|
|
246
|
+
out.push(`\n AUTHORED (${String(plan.authored.length)}) — a human decision, read both sides:\n`);
|
|
247
|
+
for (const f of plan.authored) out.push(` · ${f}\n`);
|
|
248
|
+
}
|
|
249
|
+
return out.join('');
|
|
93
250
|
}
|
|
94
251
|
|
|
95
252
|
/** Resolve the base this branch will actually merge into. */
|
|
@@ -125,7 +282,7 @@ export function resolveBase(repo: string, override: string | null): { base: stri
|
|
|
125
282
|
export function sync(repo: string, baseOverride: string | null, dryRun: boolean): Plan {
|
|
126
283
|
const { base, how } = resolveBase(repo, baseOverride);
|
|
127
284
|
if (base === null) {
|
|
128
|
-
return { exit: 1, message: `cannot resolve a base to update against — ${how}.`, generated: [], authored: [], scanned: 0 };
|
|
285
|
+
return { exit: 1, message: `cannot resolve a base to update against — ${how}.`, generated: [], remeasured: [], authored: [], scanned: 0 };
|
|
129
286
|
}
|
|
130
287
|
|
|
131
288
|
const fetched = sh('git', ['fetch', 'origin', '--prune'], repo);
|
|
@@ -136,6 +293,7 @@ export function sync(repo: string, baseOverride: string | null, dryRun: boolean)
|
|
|
136
293
|
exit: 0,
|
|
137
294
|
message: `unverified — could not fetch origin (${fetched.err.split('\n')[0] ?? '?'}). Base freshness NOT checked.`,
|
|
138
295
|
generated: [],
|
|
296
|
+
remeasured: [],
|
|
139
297
|
authored: [],
|
|
140
298
|
scanned: 0,
|
|
141
299
|
};
|
|
@@ -143,13 +301,14 @@ export function sync(repo: string, baseOverride: string | null, dryRun: boolean)
|
|
|
143
301
|
|
|
144
302
|
const behind = sh('git', ['rev-list', '--count', `HEAD..${base}`], repo).out.trim();
|
|
145
303
|
if (behind === '' || behind === '0') {
|
|
146
|
-
return { exit: 0, message: `already current with ${base} (${how}).`, generated: [], authored: [], scanned: 1 };
|
|
304
|
+
return { exit: 0, message: `already current with ${base} (${how}).`, generated: [], remeasured: [], authored: [], scanned: 1 };
|
|
147
305
|
}
|
|
148
306
|
if (dryRun) {
|
|
149
307
|
return {
|
|
150
308
|
exit: 0,
|
|
151
309
|
message: `${behind} commit(s) behind ${base} (${how}) — would merge it in. Dry run, nothing changed.`,
|
|
152
310
|
generated: [],
|
|
311
|
+
remeasured: [],
|
|
153
312
|
authored: [],
|
|
154
313
|
scanned: 1,
|
|
155
314
|
};
|
|
@@ -163,6 +322,7 @@ export function sync(repo: string, baseOverride: string | null, dryRun: boolean)
|
|
|
163
322
|
`merged ${base} in (${how}, was ${behind} behind). REGENERATE derived files now — a clean ` +
|
|
164
323
|
'auto-merge of a generated file is still wrong.',
|
|
165
324
|
generated: [],
|
|
325
|
+
remeasured: [],
|
|
166
326
|
authored: [],
|
|
167
327
|
scanned: 1,
|
|
168
328
|
};
|
|
@@ -173,7 +333,7 @@ export function sync(repo: string, baseOverride: string | null, dryRun: boolean)
|
|
|
173
333
|
return {
|
|
174
334
|
exit: 1,
|
|
175
335
|
message:
|
|
176
|
-
`merge of ${base} (${how}) hit ${String(split.generated.length + split.authored.length)} conflict(s). ` +
|
|
336
|
+
`merge of ${base} (${how}) hit ${String(split.generated.length + split.remeasured.length + split.authored.length)} conflict(s). ` +
|
|
177
337
|
'NOT auto-resolved: a content conflict is where a parallel session\'s work disappears.',
|
|
178
338
|
...split,
|
|
179
339
|
scanned: 1,
|
|
@@ -218,7 +378,8 @@ export function main(argv?: readonly string[]): number {
|
|
|
218
378
|
' Merges the PR base into the current branch so the PR does not go stale.\n' +
|
|
219
379
|
' Resolves the base from the open PR when there is one. A conflict is\n' +
|
|
220
380
|
' reported and never auto-resolved; generated and authored conflicts are\n' +
|
|
221
|
-
' listed separately because only the first has one correct resolution
|
|
381
|
+
' listed separately because only the first has one correct resolution;\n' +
|
|
382
|
+
' measured ratchet baselines are a third class, re-measured not merged.\n',
|
|
222
383
|
);
|
|
223
384
|
reportScanned({ gate: 'sync_pr_branch', scanned: 0, units: 'base ref(s)', roots: ['origin'], allowEmpty: 'help output' });
|
|
224
385
|
return 0;
|
|
@@ -239,18 +400,7 @@ export function main(argv?: readonly string[]): number {
|
|
|
239
400
|
}
|
|
240
401
|
|
|
241
402
|
if (plan.exit === 1) {
|
|
242
|
-
process.stdout.write(
|
|
243
|
-
if (plan.generated.length > 0) {
|
|
244
|
-
process.stdout.write(
|
|
245
|
-
`\n GENERATED (${String(plan.generated.length)}) — resolve by REGENERATING, never by mixing hunks:\n`,
|
|
246
|
-
);
|
|
247
|
-
for (const f of plan.generated) process.stdout.write(` · ${f}\n`);
|
|
248
|
-
process.stdout.write(' → git checkout --ours <file> && task sync && task generate-tools\n');
|
|
249
|
-
}
|
|
250
|
-
if (plan.authored.length > 0) {
|
|
251
|
-
process.stdout.write(`\n AUTHORED (${String(plan.authored.length)}) — a human decision, read both sides:\n`);
|
|
252
|
-
for (const f of plan.authored) process.stdout.write(` · ${f}\n`);
|
|
253
|
-
}
|
|
403
|
+
process.stdout.write(renderConflictReport(plan));
|
|
254
404
|
} else if (plan.message.startsWith('unverified')) {
|
|
255
405
|
// Loud even under --quiet: unverified reported silently is
|
|
256
406
|
// indistinguishable from verified, which is the defect being closed.
|
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `commands ls --candidates` — the surface-reduction report of roadmap step 3.4
|
|
3
|
-
* (`road-to-inbox-harvest-2026-08-b-release-integrity`).
|
|
4
|
-
*
|
|
5
|
-
* Every assertion derives its expectation from the synthetic input rather than
|
|
6
|
-
* pinning a literal the implementation happens to emit, so the suite cannot go
|
|
7
|
-
* green for the wrong reason. The report is deliberately built from the
|
|
8
|
-
* discovery manifest ALONE — no census file, no `utilization_report` import —
|
|
9
|
-
* and the tests pin exactly that: the honesty band must survive, and the
|
|
10
|
-
* ownership pointers must not be dropped by a later edit.
|
|
11
|
-
*/
|
|
12
|
-
import { describe, expect, it } from 'vitest';
|
|
13
|
-
import { buildCandidatesReport, renderCandidates, runCommandsLs, CANDIDATES_INCOMPATIBLE, REDUCTION_OWNERS, REPORT_ONLY_NOTICE, TEXT_LIST_CAP, } from './commands.js';
|
|
14
|
-
function cmd(slug, pack, extra = {}) {
|
|
15
|
-
return {
|
|
16
|
-
path: `src/domains/${pack}/${slug}/command.md`,
|
|
17
|
-
category: 'command',
|
|
18
|
-
name: slug,
|
|
19
|
-
slug,
|
|
20
|
-
pack,
|
|
21
|
-
visibility: 'internal',
|
|
22
|
-
workspaces: [],
|
|
23
|
-
packs: [pack],
|
|
24
|
-
lifecycle: 'stable',
|
|
25
|
-
trust: { level: 'core', confidence: 'high', human_review_required: false },
|
|
26
|
-
install: { default: true, removable: false },
|
|
27
|
-
intent: `do ${slug}`,
|
|
28
|
-
...extra,
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
/** An artefact with NO `intent` key at all — distinct from `intent: ''`, and the
|
|
32
|
-
* shape `exactOptionalPropertyTypes` forces us to build by omission. */
|
|
33
|
-
function cmdWithoutIntent(slug, pack, visibility) {
|
|
34
|
-
const { intent: _omitted, ...rest } = cmd(slug, pack, { visibility });
|
|
35
|
-
return rest;
|
|
36
|
-
}
|
|
37
|
-
/** Mixed fixture: two absorbed-name commands, two undocumented, three packs of
|
|
38
|
-
* unequal weight. */
|
|
39
|
-
const FIXTURE = [
|
|
40
|
-
cmd('alpha', 'engineering-base', { visibility: 'visible' }),
|
|
41
|
-
cmd('bravo', 'engineering-base', { visibility: 'advanced' }),
|
|
42
|
-
cmd('charlie', 'engineering-base', { visibility: 'internal', intent: '' }),
|
|
43
|
-
cmd('delta', 'frontend-design', { visibility: 'visible', replaces: ['old-delta'] }),
|
|
44
|
-
cmd('echo', 'frontend-design', { visibility: 'internal', replaces: ['old-echo', 'older-echo'] }),
|
|
45
|
-
cmdWithoutIntent('foxtrot', 'finance-basic', 'advanced'),
|
|
46
|
-
];
|
|
47
|
-
describe('buildCandidatesReport', () => {
|
|
48
|
-
const report = buildCandidatesReport(FIXTURE);
|
|
49
|
-
it('counts the whole estate it was given', () => {
|
|
50
|
-
expect(report.total).toBe(FIXTURE.length);
|
|
51
|
-
});
|
|
52
|
-
it('partitions visibility exhaustively — the buckets sum to the total', () => {
|
|
53
|
-
const summed = Object.values(report.byVisibility).reduce((a, b) => a + b, 0);
|
|
54
|
-
expect(summed).toBe(FIXTURE.length);
|
|
55
|
-
});
|
|
56
|
-
it('collects the commands that ABSORBED prior names, named explicitly', () => {
|
|
57
|
-
// Named rather than recomputed from the implementation predicate: the
|
|
58
|
-
// first version of this bucket inverted the field's meaning, and a test
|
|
59
|
-
// that re-derives `(replaces ?? []).length > 0` certifies whatever the
|
|
60
|
-
// code does — including the inversion.
|
|
61
|
-
expect(report.absorbedNames.map((r) => r.slug)).toEqual(['delta', 'echo']);
|
|
62
|
-
expect(report.absorbedNames.map((r) => r.slug)).not.toContain('alpha');
|
|
63
|
-
});
|
|
64
|
-
it('carries each absorbed-name list through unchanged', () => {
|
|
65
|
-
for (const row of report.absorbedNames) {
|
|
66
|
-
const source = FIXTURE.find((c) => c.slug === row.slug);
|
|
67
|
-
expect(row.replaces).toEqual(source?.replaces ?? []);
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
it('treats an empty-string intent as undocumented, not as documented', () => {
|
|
71
|
-
const expected = FIXTURE
|
|
72
|
-
.filter((c) => (c.intent ?? '').trim() === '')
|
|
73
|
-
.map((c) => c.slug)
|
|
74
|
-
.sort();
|
|
75
|
-
expect(report.noIntent.map((r) => r.slug)).toEqual(expected);
|
|
76
|
-
// Guard the boundary the implementation could get wrong in either
|
|
77
|
-
// direction: '' and undefined both count, a real string never does.
|
|
78
|
-
expect(expected).toContain('charlie');
|
|
79
|
-
expect(expected).toContain('foxtrot');
|
|
80
|
-
expect(expected).not.toContain('alpha');
|
|
81
|
-
});
|
|
82
|
-
it('orders packs by weight descending', () => {
|
|
83
|
-
const counts = report.byPack.map(([, n]) => n);
|
|
84
|
-
expect([...counts]).toEqual([...counts].sort((a, b) => b - a));
|
|
85
|
-
const summed = counts.reduce((a, b) => a + b, 0);
|
|
86
|
-
expect(summed).toBe(FIXTURE.length);
|
|
87
|
-
});
|
|
88
|
-
it('breaks a pack tie by name — exercised on an actual tie', () => {
|
|
89
|
-
// The mixed fixture has counts 3/2/1 and never hits the tie-break, so
|
|
90
|
-
// the previous version of this test asserted a branch it never reached.
|
|
91
|
-
const tied = buildCandidatesReport([
|
|
92
|
-
cmd('one', 'zulu'),
|
|
93
|
-
cmd('two', 'alpha'),
|
|
94
|
-
]);
|
|
95
|
-
expect(tied.byPack.map(([p]) => p)).toEqual(['alpha', 'zulu']);
|
|
96
|
-
});
|
|
97
|
-
it('is byte-stable across input permutations — the report is a set view', () => {
|
|
98
|
-
const shuffled = [...FIXTURE].reverse();
|
|
99
|
-
expect(renderCandidates(buildCandidatesReport(shuffled)))
|
|
100
|
-
.toBe(renderCandidates(buildCandidatesReport(FIXTURE)));
|
|
101
|
-
});
|
|
102
|
-
});
|
|
103
|
-
describe('buildCandidatesReport — empty estate', () => {
|
|
104
|
-
it('reports a measured zero rather than throwing or omitting sections', () => {
|
|
105
|
-
const empty = buildCandidatesReport([]);
|
|
106
|
-
expect(empty.total).toBe(0);
|
|
107
|
-
expect(empty.absorbedNames).toEqual([]);
|
|
108
|
-
expect(empty.noIntent).toEqual([]);
|
|
109
|
-
expect(empty.byPack).toEqual([]);
|
|
110
|
-
const text = renderCandidates(empty);
|
|
111
|
-
// An absent section would let a real zero read as a missing check.
|
|
112
|
-
expect(text).toContain('measured zero');
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
describe('renderCandidates — the honesty band', () => {
|
|
116
|
-
const text = renderCandidates(buildCandidatesReport(FIXTURE));
|
|
117
|
-
it('states up front that it decides nothing', () => {
|
|
118
|
-
expect(text.split('\n')[0]).toMatch(/report-only/i);
|
|
119
|
-
});
|
|
120
|
-
it('names the usage-evidence owner it deliberately does not import', () => {
|
|
121
|
-
expect(text).toContain('utilization_report');
|
|
122
|
-
});
|
|
123
|
-
it('warns that both census snapshots are dated, not current', () => {
|
|
124
|
-
expect(text).toContain('docs/SKILL_CENSUS.md');
|
|
125
|
-
expect(text).toContain('docs/artefact-census.md');
|
|
126
|
-
expect(text).toMatch(/point-in-time|do not\s+read their numbers as current/i);
|
|
127
|
-
});
|
|
128
|
-
it('hands the reduction targets to their owning roadmaps, all of them', () => {
|
|
129
|
-
for (const owner of REDUCTION_OWNERS)
|
|
130
|
-
expect(text).toContain(owner);
|
|
131
|
-
expect(REDUCTION_OWNERS.length).toBeGreaterThan(0);
|
|
132
|
-
});
|
|
133
|
-
it('never presents itself as a prune instruction', () => {
|
|
134
|
-
// Assert the exported contract, not a hand-copied sentence — a reworded
|
|
135
|
-
// disclaimer stays covered, a DELETED one fails.
|
|
136
|
-
expect(text).toContain(REPORT_ONLY_NOTICE);
|
|
137
|
-
});
|
|
138
|
-
it('states that the absorbed-name bucket is NOT a retirement class', () => {
|
|
139
|
-
// The defect this pins: the bucket was first labelled "deprecation
|
|
140
|
-
// shims", i.e. the exact inverse of what `replaces` means.
|
|
141
|
-
expect(text).not.toMatch(/deprecation shims +\d/);
|
|
142
|
-
expect(text).toMatch(/NOT a retirement class/);
|
|
143
|
-
expect(text).toContain('absorbed prior names');
|
|
144
|
-
});
|
|
145
|
-
it('reports the real shim class as not computable, with its canonical figure', () => {
|
|
146
|
-
expect(text).toMatch(/deprecation shims\s+not computable/);
|
|
147
|
-
expect(text).toContain('superseded_by');
|
|
148
|
-
expect(text).toContain('0 shims of 196');
|
|
149
|
-
});
|
|
150
|
-
it('renders every absorbed-name row it counted, with its absorbed ids', () => {
|
|
151
|
-
const report = buildCandidatesReport(FIXTURE);
|
|
152
|
-
for (const row of report.absorbedNames) {
|
|
153
|
-
expect(text).toContain(row.slug);
|
|
154
|
-
for (const prior of row.replaces)
|
|
155
|
-
expect(text).toContain(prior);
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
});
|
|
159
|
-
describe('runCommandsLs — --candidates refuses the narrowing flags', () => {
|
|
160
|
-
// Regression: each of these silently produced a whole-estate report, and a
|
|
161
|
-
// typo'd --profile exited 0 where plain `ls` exits 1.
|
|
162
|
-
for (const flag of CANDIDATES_INCOMPATIBLE) {
|
|
163
|
-
it(`exits 1 when combined with ${flag}`, () => {
|
|
164
|
-
const opts = { candidates: true };
|
|
165
|
-
if (flag === '--pack')
|
|
166
|
-
opts['pack'] = 'git';
|
|
167
|
-
if (flag === '--visible')
|
|
168
|
-
opts['visible'] = true;
|
|
169
|
-
if (flag === '--profile')
|
|
170
|
-
opts['profile'] = 'bogus';
|
|
171
|
-
if (flag === '--expanded')
|
|
172
|
-
opts['expanded'] = true;
|
|
173
|
-
expect(runCommandsLs(opts)).toBe(1);
|
|
174
|
-
});
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
describe('renderCandidates — an unrecognised visibility value cannot vanish', () => {
|
|
178
|
-
// `visibility` is a free string in the manifest (ADR-092 named the field,
|
|
179
|
-
// nothing pins its domain). Rendering only the three known labels made the
|
|
180
|
-
// printed breakdown silently disagree with the total — the exact false-green
|
|
181
|
-
// shape a report must not have.
|
|
182
|
-
const withUnknown = [
|
|
183
|
-
cmd('known', 'engineering-base', { visibility: 'visible' }),
|
|
184
|
-
cmd('odd-one', 'engineering-base', { visibility: 'experimental' }),
|
|
185
|
-
cmd('odd-two', 'engineering-base', { visibility: 'experimental' }),
|
|
186
|
-
];
|
|
187
|
-
const report = buildCandidatesReport(withUnknown);
|
|
188
|
-
const text = renderCandidates(report);
|
|
189
|
-
it('counts the unrecognised value rather than dropping it', () => {
|
|
190
|
-
expect(report.byVisibility['experimental']).toBe(2);
|
|
191
|
-
const summed = Object.values(report.byVisibility).reduce((a, b) => a + b, 0);
|
|
192
|
-
expect(summed).toBe(withUnknown.length);
|
|
193
|
-
});
|
|
194
|
-
it('renders it, so the printed breakdown sums to the printed total', () => {
|
|
195
|
-
expect(text).toContain('experimental');
|
|
196
|
-
// Sum only the visibility block: the run of bucket lines directly
|
|
197
|
-
// following the `surface` line. (A wider filter also matched the
|
|
198
|
-
// owning-packs block, which is why the earlier version of this test
|
|
199
|
-
// carried a variable that did not hold what its name claimed.)
|
|
200
|
-
const rows = text.split('\n');
|
|
201
|
-
const start = rows.findIndex((l) => l.startsWith('surface '));
|
|
202
|
-
const block = [];
|
|
203
|
-
for (const line of rows.slice(start + 1)) {
|
|
204
|
-
const m = line.match(/^ {2}(\S+) +(\d+)$/);
|
|
205
|
-
if (!m)
|
|
206
|
-
break;
|
|
207
|
-
block.push(Number(m[2]));
|
|
208
|
-
}
|
|
209
|
-
expect(block).toHaveLength(4);
|
|
210
|
-
expect(block.reduce((a, b) => a + b, 0)).toBe(report.total);
|
|
211
|
-
});
|
|
212
|
-
it('keeps the JSON record key order deterministic too, not just the render', () => {
|
|
213
|
-
// The fix first sorted unknowns in the renderer only, leaving the record
|
|
214
|
-
// a --json consumer reads in first-seen order.
|
|
215
|
-
const forward = buildCandidatesReport([
|
|
216
|
-
cmd('a', 'p', { visibility: 'zeta' }),
|
|
217
|
-
cmd('b', 'p', { visibility: 'alpha' }),
|
|
218
|
-
]);
|
|
219
|
-
const reversed = buildCandidatesReport([
|
|
220
|
-
cmd('b', 'p', { visibility: 'alpha' }),
|
|
221
|
-
cmd('a', 'p', { visibility: 'zeta' }),
|
|
222
|
-
]);
|
|
223
|
-
expect(Object.keys(forward.byVisibility)).toEqual(Object.keys(reversed.byVisibility));
|
|
224
|
-
expect(Object.keys(forward.byVisibility).slice(-2)).toEqual(['alpha', 'zeta']);
|
|
225
|
-
});
|
|
226
|
-
it('keeps the known labels ahead of the unrecognised one, for byte stability', () => {
|
|
227
|
-
const order = [...text.matchAll(/^ {2}(visible|advanced|internal|experimental) +\d+$/gm)]
|
|
228
|
-
.map((m) => m[1]);
|
|
229
|
-
expect(order[order.length - 1]).toBe('experimental');
|
|
230
|
-
});
|
|
231
|
-
});
|
|
232
|
-
describe('renderCandidates — the text-mode cap is named, never silent', () => {
|
|
233
|
-
/** One more undocumented command than the cap allows, so truncation bites. */
|
|
234
|
-
const over = Array.from({ length: TEXT_LIST_CAP + 3 }, (_unused, i) => cmd(`undoc-${String(i).padStart(3, '0')}`, 'engineering-base', { intent: '' }));
|
|
235
|
-
const report = buildCandidatesReport(over);
|
|
236
|
-
const text = renderCandidates(report);
|
|
237
|
-
it('keeps the COUNT honest even though the list is truncated', () => {
|
|
238
|
-
expect(report.noIntent.length).toBe(over.length);
|
|
239
|
-
expect(text).toContain(`no stated intent ${over.length}`);
|
|
240
|
-
});
|
|
241
|
-
it('states how many rows it withheld, derived from the input', () => {
|
|
242
|
-
expect(text).toContain(`… and ${over.length - TEXT_LIST_CAP} more`);
|
|
243
|
-
});
|
|
244
|
-
it('caps the enumeration at exactly TEXT_LIST_CAP rows', () => {
|
|
245
|
-
const listed = over.filter((c) => text.includes(` ${c.slug} (`)).length;
|
|
246
|
-
expect(listed).toBe(TEXT_LIST_CAP);
|
|
247
|
-
});
|
|
248
|
-
it('never caps the structured payload', () => {
|
|
249
|
-
// --json consumers get the whole set; the cap is a text-mode concern.
|
|
250
|
-
expect(report.noIntent).toHaveLength(over.length);
|
|
251
|
-
});
|
|
252
|
-
it('adds no truncation notice when the set fits', () => {
|
|
253
|
-
const fits = renderCandidates(buildCandidatesReport(over.slice(0, TEXT_LIST_CAP)));
|
|
254
|
-
expect(fits).not.toContain('more — the full set is in --json');
|
|
255
|
-
});
|
|
256
|
-
});
|
|
257
|
-
//# sourceMappingURL=commands.candidates.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"commands.candidates.test.js","sourceRoot":"","sources":["../../../src/cli/commands/commands.candidates.test.ts"],"names":[],"mappings":"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"}
|