@vibecompass/vibecompass 0.10.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/docs-review.js +107 -6
- package/src/workflows/registry.js +4 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.10.1 - 2026-06-14
|
|
4
|
+
|
|
5
|
+
- Add completeness-inventory guidance to docs-review so coverage plans account for accepted, deferred, and missing subsystems instead of silently omitting large areas.
|
|
6
|
+
- Score accepted coverage against the optional completeness inventory denominator when present, with a backwards-compatible fallback for older coverage plans.
|
|
7
|
+
- Add soft parser warnings for modern coverage plans that omit completeness inventory or under-explain accepted/deferred/missing inventory items.
|
|
8
|
+
- Add prose-only surface matrix guidance for feature docs while keeping `systems[]` as derived overview metadata rather than a second projected graph.
|
|
9
|
+
|
|
3
10
|
## 0.10.0 - 2026-06-14
|
|
4
11
|
|
|
5
12
|
- Make docs-review prompts mode-aware: interactive AI sessions stop at the coverage-plan approval gate, while `--run-local` and hosted single-turn runs emit fenced proposal material for later apply/proposal review.
|
package/package.json
CHANGED
package/src/docs-review.js
CHANGED
|
@@ -9,7 +9,7 @@ import { parseSimpleYaml } from './simple-yaml.js';
|
|
|
9
9
|
import { readSyncCursor, resolveSyncBinding } from './sync-binding.js';
|
|
10
10
|
import { PACKAGE_VERSION } from './version.js';
|
|
11
11
|
|
|
12
|
-
const DOCS_REVIEW_PROMPT_VERSION = 'VibeCompass Docs Review Prompt
|
|
12
|
+
const DOCS_REVIEW_PROMPT_VERSION = 'VibeCompass Docs Review Prompt v6';
|
|
13
13
|
const ARCHITECTURE_DOC_SOFT_SIZE_LIMIT_BYTES = 12000;
|
|
14
14
|
const COVERAGE_PLAN_OUTPUT_VERSION = 1;
|
|
15
15
|
const COVERAGE_PLAN_STATUSES = new Set(['accepted', 'deferred', 'missing']);
|
|
@@ -921,10 +921,12 @@ function buildCoverageProjection(blocks, options) {
|
|
|
921
921
|
|
|
922
922
|
const ids = new Set();
|
|
923
923
|
const areas = plan.areas.map((area, index) => normalizeCoverageArea(area, index, ids));
|
|
924
|
+
const areaById = new Map(areas.map((area) => [area.id, area]));
|
|
925
|
+
const hasCompletenessInventory = Object.prototype.hasOwnProperty.call(plan, 'completeness_inventory');
|
|
926
|
+
const completenessInventory = normalizeCompletenessInventory(plan.completeness_inventory, areaById);
|
|
924
927
|
const statuses = countBy(areas, 'status');
|
|
925
928
|
const coverage_levels = countBy(areas, 'coverage');
|
|
926
|
-
const
|
|
927
|
-
const acceptedCount = statuses.accepted ?? 0;
|
|
929
|
+
const inventory_statuses = countBy(completenessInventory, 'status');
|
|
928
930
|
|
|
929
931
|
return {
|
|
930
932
|
version: COVERAGE_PLAN_OUTPUT_VERSION,
|
|
@@ -937,13 +939,30 @@ function buildCoverageProjection(blocks, options) {
|
|
|
937
939
|
...(normalizeOptionalString(plan.topology) ? { topology: normalizeOptionalString(plan.topology) } : {}),
|
|
938
940
|
...(normalizeCoverageTaxonomy(plan.taxonomy) ? { taxonomy: normalizeCoverageTaxonomy(plan.taxonomy) } : {}),
|
|
939
941
|
area_count: areas.length,
|
|
940
|
-
|
|
942
|
+
...(hasCompletenessInventory ? {
|
|
943
|
+
completeness_inventory: completenessInventory,
|
|
944
|
+
inventory_count: completenessInventory.length,
|
|
945
|
+
inventory_statuses,
|
|
946
|
+
} : {}),
|
|
947
|
+
coverage_score: calculateCoverageScore({ areas, statuses, completenessInventory, hasCompletenessInventory }),
|
|
941
948
|
statuses,
|
|
942
949
|
coverage_levels,
|
|
943
950
|
areas,
|
|
944
951
|
};
|
|
945
952
|
}
|
|
946
953
|
|
|
954
|
+
function calculateCoverageScore({ areas, statuses, completenessInventory, hasCompletenessInventory }) {
|
|
955
|
+
if (hasCompletenessInventory) {
|
|
956
|
+
const denominator = completenessInventory.length;
|
|
957
|
+
const acceptedCount = completenessInventory.filter((item) => item.status === 'accepted').length;
|
|
958
|
+
return denominator === 0 ? null : Number((acceptedCount / denominator).toFixed(4));
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
const denominator = areas.length;
|
|
962
|
+
const acceptedCount = statuses.accepted ?? 0;
|
|
963
|
+
return denominator === 0 ? null : Number((acceptedCount / denominator).toFixed(4));
|
|
964
|
+
}
|
|
965
|
+
|
|
947
966
|
function normalizeCoverageTaxonomy(value) {
|
|
948
967
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
949
968
|
return null;
|
|
@@ -961,6 +980,55 @@ function normalizeCoverageTaxonomy(value) {
|
|
|
961
980
|
};
|
|
962
981
|
}
|
|
963
982
|
|
|
983
|
+
function normalizeCompletenessInventory(value, areaById) {
|
|
984
|
+
if (value === undefined || value === null) {
|
|
985
|
+
return [];
|
|
986
|
+
}
|
|
987
|
+
if (!Array.isArray(value)) {
|
|
988
|
+
throw new Error('Coverage plan completeness_inventory must be an array when present.');
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
const ids = new Set();
|
|
992
|
+
return value.map((item, index) => normalizeCompletenessInventoryItem(item, index, ids, areaById));
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
function normalizeCompletenessInventoryItem(item, index, ids, areaById) {
|
|
996
|
+
if (!item || typeof item !== 'object' || Array.isArray(item)) {
|
|
997
|
+
throw new Error(`Coverage plan completeness_inventory item at index ${index} must be an object.`);
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
const id = normalizeOptionalString(item.id);
|
|
1001
|
+
if (!id) {
|
|
1002
|
+
throw new Error(`Coverage plan completeness_inventory item at index ${index} requires non-empty "id".`);
|
|
1003
|
+
}
|
|
1004
|
+
if (ids.has(id)) {
|
|
1005
|
+
throw new Error(`Coverage plan completeness_inventory contains duplicate item id: ${id}`);
|
|
1006
|
+
}
|
|
1007
|
+
ids.add(id);
|
|
1008
|
+
|
|
1009
|
+
const status = normalizeOptionalString(item.status);
|
|
1010
|
+
if (!COVERAGE_PLAN_STATUSES.has(status)) {
|
|
1011
|
+
throw new Error(`Coverage plan completeness_inventory item "${id}" requires status to be accepted, deferred, or missing.`);
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
const coverageAreaIds = normalizeStringArray(item.coverage_area_ids);
|
|
1015
|
+
for (const areaId of coverageAreaIds) {
|
|
1016
|
+
if (!areaById.has(areaId)) {
|
|
1017
|
+
throw new Error(`Coverage plan completeness_inventory item "${id}" references unknown coverage area id: ${areaId}`);
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
return {
|
|
1022
|
+
id,
|
|
1023
|
+
...(normalizeOptionalString(item.kind) ? { kind: normalizeOptionalString(item.kind) } : {}),
|
|
1024
|
+
...(normalizeOptionalString(item.label) ? { label: normalizeOptionalString(item.label) } : {}),
|
|
1025
|
+
status,
|
|
1026
|
+
...(coverageAreaIds.length > 0 ? { coverage_area_ids: coverageAreaIds } : {}),
|
|
1027
|
+
evidence: normalizeStringArray(item.evidence),
|
|
1028
|
+
blindspots: normalizeStringArray(item.blindspots),
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
|
|
964
1032
|
function normalizeCoverageArea(area, index, ids) {
|
|
965
1033
|
if (!area || typeof area !== 'object' || Array.isArray(area)) {
|
|
966
1034
|
throw new Error(`Coverage plan area at index ${index} must be an object.`);
|
|
@@ -1134,15 +1202,30 @@ function createCoveragePlanQualityWarnings(coverageProjection, anchors) {
|
|
|
1134
1202
|
return [];
|
|
1135
1203
|
}
|
|
1136
1204
|
|
|
1205
|
+
const warnings = [];
|
|
1206
|
+
const hasModernCoverageMetadata = Boolean(coverageProjection.topology || coverageProjection.taxonomy);
|
|
1207
|
+
const hasCompletenessInventory = Array.isArray(coverageProjection.completeness_inventory);
|
|
1208
|
+
if (hasModernCoverageMetadata && !hasCompletenessInventory) {
|
|
1209
|
+
warnings.push('missing_completeness_inventory: coverage plan should enumerate discovered subsystems so deferred or missing areas cannot be silently omitted.');
|
|
1210
|
+
} else if (hasCompletenessInventory) {
|
|
1211
|
+
for (const item of coverageProjection.completeness_inventory) {
|
|
1212
|
+
if (item.status === 'accepted' && (!Array.isArray(item.coverage_area_ids) || item.coverage_area_ids.length === 0)) {
|
|
1213
|
+
warnings.push(`accepted_inventory_without_area: completeness_inventory item "${item.id}" is accepted but does not reference coverage_area_ids.`);
|
|
1214
|
+
}
|
|
1215
|
+
if (item.status !== 'accepted' && (!Array.isArray(item.blindspots) || item.blindspots.length === 0)) {
|
|
1216
|
+
warnings.push(`incomplete_inventory_blindspot: completeness_inventory item "${item.id}" is ${item.status} but does not explain the gap in blindspots.`);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1137
1221
|
const hasPriorAnchors =
|
|
1138
1222
|
(anchors?.architectureDocs?.length ?? 0) > 0 ||
|
|
1139
1223
|
(anchors?.projectMapFeatures?.length ?? 0) > 0 ||
|
|
1140
1224
|
Boolean(anchors?.coverage);
|
|
1141
1225
|
if (!hasPriorAnchors) {
|
|
1142
|
-
return
|
|
1226
|
+
return warnings;
|
|
1143
1227
|
}
|
|
1144
1228
|
|
|
1145
|
-
const warnings = [];
|
|
1146
1229
|
for (const area of coverageProjection.areas) {
|
|
1147
1230
|
if (!area.anchor_action) {
|
|
1148
1231
|
warnings.push(`missing_anchor_action: coverage area "${area.id}" should classify prior docs or project-map identities when re-review anchors exist.`);
|
|
@@ -2025,14 +2108,17 @@ function renderReviewPrompt(options) {
|
|
|
2025
2108
|
'Stage 1 — Evidence inventory:',
|
|
2026
2109
|
'- Build a compact repo inventory from file paths, manifests/config files, route/job/test directories, and existing architecture frontmatter before reading large file bodies.',
|
|
2027
2110
|
'- Identify the project topology before choosing docs: single-repo/monolith, multi-repo, multi-surface, package/CLI, workers/services, mobile app, or mixed. State the topology in the coverage plan.',
|
|
2111
|
+
'- Build a completeness inventory of discovered apps/repos, routes/screens, API endpoints, tables/storage, jobs/cron/tasks, auth/session flows, external integrations, platform surfaces, and product features. Keep it subsystem-level, not a raw file dump.',
|
|
2028
2112
|
'- Mine finalized session notes for decision candidates and product constraints, but cap proposed decisions to the five highest-value architecture choices.',
|
|
2029
2113
|
'- Identify candidate domains, features, components, ownership boundaries, user journey entry points, feature-to-feature relationships, and system-layer connections with concrete `repo:path` evidence.',
|
|
2114
|
+
'- Separate product features from runtime surfaces. Web, mobile, backend/API, database/storage, jobs, external integrations, and deployment/runtime are surfaces or systems that participate in features; do not treat them as competing feature categories unless the project itself is a platform/tooling project.',
|
|
2030
2115
|
'- Do not fetch or summarize broad source bodies until the coverage plan says a file is needed.',
|
|
2031
2116
|
'',
|
|
2032
2117
|
'Stage 2 — Coverage plan:',
|
|
2033
2118
|
'- Propose the smallest useful architecture-doc set that will let future agents understand the project and retrieve targeted context.',
|
|
2034
2119
|
'- The minimum useful set must cover: user journey, project/system map (frontend/backend/API/data/integration structure and connections), and summaries of the core journey-facing features.',
|
|
2035
2120
|
'- Prioritize entry points, user-flow/gating relationships, data ownership, external integrations, jobs/async boundaries, auth/security boundaries, and test surfaces.',
|
|
2121
|
+
'- Account for each completeness-inventory item in the coverage plan as accepted, deferred, or missing. Do not inflate coverage by omitting large discovered subsystems; honest deferred/missing entries are expected when the first pass cannot cover everything.',
|
|
2036
2122
|
'- Choose one primary taxonomy axis from topology evidence and keep it stable: single-repo/monolith may default domain-first; multi-repo or multi-surface projects may use platform/repo-first or domain-first with per-surface components. Do not mix taxonomy axes at the same tier unless you explicitly propose and justify a restructuring.',
|
|
2037
2123
|
'- For every prior architecture doc or project-map feature identity in Re-review Anchors, classify the plan action as `reuse`, `update`, `split`, `merge`, `defer`, or `replace`. Use `new` only for areas not represented by the prior tree.',
|
|
2038
2124
|
'- Every `split`, `merge`, or `replace` action requires an evidence-backed anchor reason before prose generation. No unexplained slug rename is allowed.',
|
|
@@ -2058,6 +2144,8 @@ function renderReviewPrompt(options) {
|
|
|
2058
2144
|
'- frontmatter fields: `domain`, `feature`, `component`, `status`, plus `repo` or `repos` when implementation-scoped',
|
|
2059
2145
|
'- body sections: `## Description`, `## Review metadata`, `## Details`, `## Retrieval guidance`, `## Next steps`, `## Involved files`',
|
|
2060
2146
|
'- overview docs may add compact peer sections for Stage 1 backbone outputs when useful: `## Topology`, `## Core feature inventory`, `## User journey map`, `## Project systems map`, and `## Coverage and quality summary`',
|
|
2147
|
+
'- feature docs may add a compact `## Surface matrix` prose table when multiple surfaces participate. Keep it evidence-sized: include participating surfaces with concrete `repo:path` evidence and explicit N/A rows only when an absence is important to retrieval. Do not emit a new machine-readable surface block.',
|
|
2148
|
+
'- surface/platform ownership docs should stay inside the existing contract, typically as `architecture/platform/<surface>/<component>.md`; do not introduce a top-level `systems/` tree.',
|
|
2061
2149
|
'',
|
|
2062
2150
|
'Use this exact Review metadata sub-header in every generated architecture doc:',
|
|
2063
2151
|
'',
|
|
@@ -2121,6 +2209,7 @@ function renderReviewPrompt(options) {
|
|
|
2121
2209
|
'',
|
|
2122
2210
|
'Only include relationships supported by evidence. Prefer `navigates_to` and `gates` for the main user journey; use `depends_on` and `writes_to` for supporting system relationships. If useful journey links cannot be inferred, state that as a coverage gap rather than inventing links.',
|
|
2123
2211
|
'`systems[]` is optional derived overview metadata, not a new canonical taxonomy, relationship schema, or projection source. Include it only when evidence identifies runtime/deployable units or external systems; treat `owns_features` as documentation-only grouping, put user-journey links in `relationships[]`, and record uncertain systems or system-to-system connections as blindspots.',
|
|
2212
|
+
'Per-feature surface matrices are derived prose. `systems[].owns_features` remains the only machine-readable system-to-feature hint in this release; do not duplicate that graph in another parsed block.',
|
|
2124
2213
|
'',
|
|
2125
2214
|
'## Output Contract',
|
|
2126
2215
|
'First provide a concise findings summary with:',
|
|
@@ -2129,6 +2218,7 @@ function renderReviewPrompt(options) {
|
|
|
2129
2218
|
'- user journey and project/system map coverage',
|
|
2130
2219
|
'- gaps/blindspots',
|
|
2131
2220
|
'- evidence inventory summary',
|
|
2221
|
+
'- completeness inventory summary with accepted/deferred/missing accounting',
|
|
2132
2222
|
'- topology and chosen taxonomy axis',
|
|
2133
2223
|
'- coverage plan and proposed architecture docs',
|
|
2134
2224
|
'- prior-doc anchor classifications and reasons',
|
|
@@ -2146,6 +2236,17 @@ function renderReviewPrompt(options) {
|
|
|
2146
2236
|
' "primary_axis": "domain-first | platform-first | repo-first | other",',
|
|
2147
2237
|
' "rationale": "Why this axis matches the evidence and how it avoids mixed tiers"',
|
|
2148
2238
|
' },',
|
|
2239
|
+
' "completeness_inventory": [',
|
|
2240
|
+
' {',
|
|
2241
|
+
' "id": "stable-subsystem-id",',
|
|
2242
|
+
' "kind": "feature | surface | route | screen | api | data | storage | job | integration | auth | deployment | other",',
|
|
2243
|
+
' "label": "Short discovered subsystem label",',
|
|
2244
|
+
' "status": "accepted | deferred | missing",',
|
|
2245
|
+
' "coverage_area_ids": ["stable-area-id"],',
|
|
2246
|
+
' "evidence": ["repo:path"],',
|
|
2247
|
+
' "blindspots": ["explicit blindspot for deferred or missing items"]',
|
|
2248
|
+
' }',
|
|
2249
|
+
' ],',
|
|
2149
2250
|
' "areas": [',
|
|
2150
2251
|
' {',
|
|
2151
2252
|
' "id": "stable-area-id",',
|
|
@@ -111,11 +111,13 @@ Turn starter project memory into evidence-backed architecture docs under \`archi
|
|
|
111
111
|
2. Inspect the declared source repos in stages:
|
|
112
112
|
- inventory paths, manifests, configs, route/job/test directories, and existing architecture frontmatter first
|
|
113
113
|
- identify project topology before choosing taxonomy: single-repo/monolith, multi-repo, multi-surface, package/CLI, workers/services, mobile app, or mixed
|
|
114
|
+
- build a subsystem-level completeness inventory of apps/repos, routes/screens, APIs, tables/storage, jobs/cron/tasks, auth/session flows, external integrations, runtime surfaces, and product features
|
|
115
|
+
- distinguish product features from participating surfaces such as web, mobile, backend/API, data, jobs, integrations, and deployment/runtime
|
|
114
116
|
- produce a coverage plan before reading broad source bodies
|
|
115
117
|
- read targeted source files only when the coverage plan needs evidence
|
|
116
118
|
3. Run \`vibecompass docs-review --guided --llm <tool-name> --model <model-name>\` to record the review marker and print the canonical docs-review contract. Use the current AI tool name and model when known.
|
|
117
|
-
4. Present the evidence inventory, topology, chosen taxonomy axis, prior-doc reuse/update/split/merge/defer/replace classifications, coverage plan, backbone outputs (core feature inventory, user journey map, project systems map, coverage/quality summary), proposed architecture docs, blindspots, token-budget risks, quality report, and any decision candidates before generating accepted output. If you stop here for user approval, state clearly that no architecture docs have been applied yet and do not label proposed areas as accepted.
|
|
118
|
-
5. Draft only output the user accepts. After approval, the accepted plan must be fenced as \`vibecompass-coverage-plan version=1\`. Accepted architecture docs must be fenced as \`vibecompass-architecture-doc path=architecture/domain/feature/component.md\` blocks and must include required frontmatter: \`domain\`, \`feature\`, \`component\`, and \`status\`. The accepted \`architecture/overview/project-shape.md\` doc should include compact backbone sections and exactly one \`vibecompass-project-map version=1\` JSON block with journey-facing features, entry points, evidence-backed relationships, and minimal optional derived \`systems[]\` metadata. Accepted local decisions may be fenced as \`vibecompass-decision-recommendation target=decisions/domain.md\` blocks without D-numbers.
|
|
119
|
+
4. Present the evidence inventory, completeness inventory with accepted/deferred/missing accounting, topology, chosen taxonomy axis, prior-doc reuse/update/split/merge/defer/replace classifications, coverage plan, backbone outputs (core feature inventory, user journey map, project systems map, coverage/quality summary), proposed architecture docs, blindspots, token-budget risks, quality report, and any decision candidates before generating accepted output. If you stop here for user approval, state clearly that no architecture docs have been applied yet and do not label proposed areas as accepted.
|
|
120
|
+
5. Draft only output the user accepts. After approval, the accepted plan must be fenced as \`vibecompass-coverage-plan version=1\`. Accepted architecture docs must be fenced as \`vibecompass-architecture-doc path=architecture/domain/feature/component.md\` blocks and must include required frontmatter: \`domain\`, \`feature\`, \`component\`, and \`status\`. Feature docs may include compact prose-only surface matrices; surface/platform ownership docs stay under the existing \`architecture/platform/<surface>/<component>.md\` shape rather than a new top-level systems tree. The accepted \`architecture/overview/project-shape.md\` doc should include compact backbone sections and exactly one \`vibecompass-project-map version=1\` JSON block with journey-facing features, entry points, evidence-backed relationships, and minimal optional derived \`systems[]\` metadata. Accepted local decisions may be fenced as \`vibecompass-decision-recommendation target=decisions/domain.md\` blocks without D-numbers.
|
|
119
121
|
6. Keep each generated architecture doc focused and retrieval-oriented. Soft budget: under 12000 bytes per doc unless the extra detail is necessary and called out in review metadata or retrieval guidance.
|
|
120
122
|
7. Write the accepted fenced blocks verbatim to \`${outputPath}\`.
|
|
121
123
|
8. Run \`${applyCommand}\` to validate and apply the accepted blocks. If \`vibecompass\` is not installed on PATH, run \`${npxApplyCommand}\` instead. Only report docs-review as applied after this command succeeds. If accepted docs were written manually outside the output file, run \`vibecompass docs-review --root ${rootRelativePath} --complete\` after confirming the marker should be completed.
|