kibi-cli 2.22.1 → 2.24.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/dist/cli-operation-metadata.d.ts +1 -1
- package/dist/cli-operation-metadata.js +1 -1
- package/dist/cli-register-foundation.d.ts.map +1 -1
- package/dist/cli-register-foundation.js +1 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +51 -3
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +28 -0
- package/dist/commands/migrate.d.ts +10 -0
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +81 -9
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +15 -1
- package/dist/decision-firmness.d.ts +16 -4
- package/dist/decision-firmness.d.ts.map +1 -1
- package/dist/decision-firmness.js +29 -6
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +39 -36
- package/dist/intent-search.d.ts +2 -0
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +43 -4
- package/dist/operations/bootstrap/activation.d.ts +7 -1
- package/dist/operations/bootstrap/activation.d.ts.map +1 -1
- package/dist/operations/bootstrap/activation.js +27 -2
- package/dist/operations/bootstrap/candidate-helpers.d.ts +6 -0
- package/dist/operations/bootstrap/candidate-helpers.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidate-helpers.js +19 -0
- package/dist/operations/bootstrap/generate.d.ts.map +1 -1
- package/dist/operations/bootstrap/generate.js +56 -16
- package/dist/operations/bootstrap/guidance-actions.d.ts.map +1 -1
- package/dist/operations/bootstrap/guidance-actions.js +14 -2
- package/dist/operations/bootstrap/guidance.d.ts.map +1 -1
- package/dist/operations/bootstrap/guidance.js +6 -2
- package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -1
- package/dist/operations/bootstrap/intent-claims.js +2 -2
- package/dist/operations/bootstrap/markdown-candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/markdown-candidates.js +2 -2
- package/dist/operations/bootstrap/presentation.d.ts.map +1 -1
- package/dist/operations/bootstrap/presentation.js +75 -9
- package/dist/operations/bootstrap/types.d.ts +6 -0
- package/dist/operations/bootstrap/types.d.ts.map +1 -1
- package/dist/operations/migration/firm-supersede.d.ts +19 -0
- package/dist/operations/migration/firm-supersede.d.ts.map +1 -0
- package/dist/operations/migration/firm-supersede.js +60 -0
- package/dist/operations/migration/kb-sources.d.ts +8 -5
- package/dist/operations/migration/kb-sources.d.ts.map +1 -1
- package/dist/operations/migration/kb-sources.js +50 -14
- package/dist/operations/migration/schema6.d.ts.map +1 -1
- package/dist/operations/migration/schema6.js +52 -2
- package/dist/operations/migration/source-paths.d.ts +18 -1
- package/dist/operations/migration/source-paths.d.ts.map +1 -1
- package/dist/operations/migration/source-paths.js +111 -16
- package/dist/operations/modeling/suggest-predicates.d.ts.map +1 -1
- package/dist/operations/modeling/suggest-predicates.js +22 -7
- package/dist/operations/mutation/requirement-semantics.d.ts +19 -1
- package/dist/operations/mutation/requirement-semantics.d.ts.map +1 -1
- package/dist/operations/mutation/requirement-semantics.js +63 -2
- package/dist/operations/mutation/strict-fact.js +1 -1
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +2 -1
- package/dist/operations/planning/apply-plan.d.ts.map +1 -1
- package/dist/operations/planning/apply-plan.js +22 -2
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +49 -17
- package/dist/public/impact/analyzer.d.ts.map +1 -1
- package/dist/public/impact/analyzer.js +7 -1
- package/dist/public/impact/diagnostics.d.ts.map +1 -1
- package/dist/public/impact/diagnostics.js +16 -3
- package/dist/public/impact/types.d.ts +2 -0
- package/dist/public/impact/types.d.ts.map +1 -1
- package/dist/public/operations/catalog.d.ts +8 -3
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +10 -3
- package/dist/public/operations/check-helpers.d.ts +10 -0
- package/dist/public/operations/check-helpers.d.ts.map +1 -1
- package/dist/public/operations/check-helpers.js +54 -0
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +1 -0
- package/dist/public/operations/decision-firmness.d.ts +14 -0
- package/dist/public/operations/decision-firmness.d.ts.map +1 -1
- package/dist/public/operations/decision-firmness.js +60 -7
- package/dist/public/operations/discovery-executors.d.ts +18 -0
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +80 -8
- package/dist/public/operations/schema6-check-actions.d.ts +4 -0
- package/dist/public/operations/schema6-check-actions.d.ts.map +1 -1
- package/dist/public/operations/schema6-check-actions.js +39 -2
- package/dist/public/operations/source-path-dangling.d.ts +1 -1
- package/dist/public/operations/source-path-dangling.d.ts.map +1 -1
- package/dist/public/operations/source-path-dangling.js +11 -2
- package/dist/public/operations/specs/composite.d.ts +1 -1
- package/dist/public/operations/specs/discovery.d.ts +5 -0
- package/dist/public/operations/specs/discovery.d.ts.map +1 -1
- package/dist/public/operations/specs/discovery.js +5 -0
- package/dist/public/operations/specs/planning.d.ts +1 -1
- package/dist/public/operations/specs/planning.js +1 -1
- package/dist/public/operations/specs/reporting.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.js +6 -4
- package/dist/public/operations/specs/semantic.d.ts +1 -1
- package/dist/public/operations/specs/semantic.d.ts.map +1 -1
- package/dist/public/operations/specs/semantic.js +4 -2
- package/dist/public/operations/specs/upsert.d.ts +1 -1
- package/dist/public/operations/specs/upsert.js +1 -1
- package/dist/public/schemas/entity.js +1 -1
- package/dist/public/skills/kibi-bootstrap/SKILL.md +5 -4
- package/dist/public/skills/kibi-usage/SKILL.md +36 -16
- package/dist/public/skills/kibi-usage/resources/workflows.md +3 -1
- package/dist/schemas/entity.schema.json +1 -1
- package/dist/search-answer.d.ts +14 -0
- package/dist/search-answer.d.ts.map +1 -1
- package/dist/search-answer.js +51 -5
- package/dist/traceability/git-change-snapshot.d.ts +46 -0
- package/dist/traceability/git-change-snapshot.d.ts.map +1 -1
- package/dist/traceability/git-change-snapshot.js +187 -3
- package/dist/traceability/staged-diagnostics.d.ts.map +1 -1
- package/dist/traceability/staged-diagnostics.js +5 -6
- package/dist/traceability/staged-inventory-drift.d.ts +24 -0
- package/dist/traceability/staged-inventory-drift.d.ts.map +1 -0
- package/dist/traceability/staged-inventory-drift.js +84 -0
- package/dist/traceability/staged-symbols-manifest.d.ts.map +1 -1
- package/dist/traceability/staged-symbols-manifest.js +1 -2
- package/dist/types/entities.d.ts +2 -2
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/utils/content-freshness.d.ts +9 -0
- package/dist/utils/content-freshness.d.ts.map +1 -1
- package/dist/utils/content-freshness.js +33 -0
- package/dist/utils/kb-manifest.d.ts +7 -0
- package/dist/utils/kb-manifest.d.ts.map +1 -1
- package/dist/utils/kb-manifest.js +6 -0
- package/dist/utils/merge-driver-setup.d.ts +10 -0
- package/dist/utils/merge-driver-setup.d.ts.map +1 -0
- package/dist/utils/merge-driver-setup.js +69 -0
- package/dist/utils/rule-registry.generated.d.ts +1 -1
- package/dist/utils/rule-registry.generated.js +1 -1
- package/dist/utils/schema-version.d.ts +1 -1
- package/dist/utils/schema-version.d.ts.map +1 -1
- package/dist/utils/schema-version.js +3 -1
- package/package.json +2 -2
- package/src/public/impact/analyzer.ts +13 -1
- package/src/public/impact/diagnostics.ts +20 -3
- package/src/public/impact/types.ts +2 -0
- package/src/public/operations/check-executor.ts +16 -4
- package/src/public/operations/check-helpers.ts +65 -0
- package/src/public/operations/contracts.ts +1 -0
- package/src/public/operations/decision-firmness.ts +83 -10
- package/src/public/operations/discovery-executors.ts +124 -7
- package/src/public/operations/schema6-check-actions.ts +43 -2
- package/src/public/operations/source-path-dangling.ts +12 -2
- package/src/public/operations/specs/discovery.ts +6 -0
- package/src/public/operations/specs/planning.ts +1 -1
- package/src/public/operations/specs/reporting.ts +6 -4
- package/src/public/operations/specs/semantic.ts +4 -2
- package/src/public/operations/specs/upsert.ts +1 -1
- package/src/public/schemas/entity.ts +1 -1
- package/src/public/skills/kibi-bootstrap/SKILL.md +5 -4
- package/src/public/skills/kibi-usage/SKILL.md +36 -16
- package/src/public/skills/kibi-usage/resources/workflows.md +3 -1
- package/src/schemas/entity.schema.json +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
id: kibi-usage
|
|
3
3
|
name: Kibi Usage
|
|
4
4
|
description: Use Kibi's source-first, exact-Git, migration-aware, proof-aware operations safely across MCP or the trusted local CLI, including partial completion repair.
|
|
5
|
-
version: 2.
|
|
5
|
+
version: 2.17.0
|
|
6
6
|
kibiCompatibility: ">=1.0.0"
|
|
7
7
|
tags:
|
|
8
8
|
- kibi
|
|
@@ -92,10 +92,12 @@ it is a pointer to the knowledge, never proof. Each line answers one question:
|
|
|
92
92
|
- `Kibi knowledge for <path> (symbol manifest):` and the `- REQ-… — <symbol
|
|
93
93
|
titles>` rows: the requirements the file's symbols implement, lead
|
|
94
94
|
requirement first. Read the lead requirement with `kb_query({id})` before
|
|
95
|
-
changing behavior
|
|
95
|
+
changing behavior; add `includeBody: true` to see its authored prose, and
|
|
96
|
+
fix a stale sentence there with `kb_upsert` `document.body`.
|
|
96
97
|
- `REQ-… must keep true: FACT-…` (edit only): the ground facts the lead
|
|
97
98
|
requirement requires. An edit that breaks one of them is a requirement
|
|
98
|
-
change:
|
|
99
|
+
change: ask before changing the rule (see Decision firmness), and never
|
|
100
|
+
code around the fact.
|
|
99
101
|
- `Decision: ADR-…` (edit only): the decision behind the lead requirement.
|
|
100
102
|
- `Covered by: TEST-…` and `Test code for: …`: the tests that prove the
|
|
101
103
|
file's symbols; run or update them with the edit.
|
|
@@ -358,24 +360,40 @@ exists in `rationale`, or link the ADR that explains it.
|
|
|
358
360
|
|
|
359
361
|
Requirements and ADRs carry `firmness`, which says what you may do with them.
|
|
360
362
|
Search answers, `kb_query` rows and hook snippets show it (snippets label only
|
|
361
|
-
`[firm]` and `[exploratory]`; an unlabeled decision is
|
|
363
|
+
`[firm: ask before changing]` and `[exploratory]`; an unlabeled decision is
|
|
364
|
+
`default`).
|
|
362
365
|
|
|
363
366
|
- `firm`: a human stated it as a rule. Follow it; to change it, ask first.
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
367
|
+
A requirement or ADR with no `firmness` reads as `firm` unless an agent
|
|
368
|
+
wrote it (`origin.kind: agent`): rules people wrote, imported or carried
|
|
369
|
+
over from before origins existed are theirs. `kb_check` blocks an explicit
|
|
370
|
+
`firmness: firm` without `origin.ref` to their words, and a replacement of
|
|
371
|
+
a firm decision that is not itself firm.
|
|
372
|
+
- `default`: a delegated or agent choice (`firmness: default`, or an
|
|
373
|
+
agent-written decision without `firmness`). Follow it; supersede it only on
|
|
374
|
+
evidence that it is wrong (a failing test, a measured cost, a constraint it
|
|
375
|
+
missed), in the same change, listed under "Decisions I changed".
|
|
369
376
|
- `exploratory`: a flagged guess; revisit it when you touch the area.
|
|
370
377
|
|
|
378
|
+
**A request that conflicts with a recorded rule is a question, whatever the
|
|
379
|
+
rule's firmness.** The request is not evidence against the rule: it is the
|
|
380
|
+
conflict a person has to decide. Name the rule (id and what it requires) and
|
|
381
|
+
ask whether to change it; do not implement the request and do not supersede
|
|
382
|
+
the rule. Go ahead only when the person has said to change that rule, in this
|
|
383
|
+
task or in reply: then supersede it with `firmness: firm` and `origin.ref` to
|
|
384
|
+
their words, and say in the final answer which rule changed.
|
|
385
|
+
|
|
371
386
|
Set `firmness` from what a human actually said: only their stated rule is
|
|
372
387
|
`firm` (with `origin.ref`); "do whatever" or your own pick is `default`; a
|
|
373
|
-
guess is `exploratory`.
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
388
|
+
guess is `exploratory`. Write it explicitly whenever you record a decision,
|
|
389
|
+
including when importing rules from documents, tests or tickets (a rule a
|
|
390
|
+
person wrote there is `firm`, with `origin.ref` to that document). A
|
|
391
|
+
supersede needs `## Why this changed` in the new entity's body (at least 12
|
|
392
|
+
words): name the evidence (a failing test, a measured cost, a constraint the
|
|
393
|
+
old decision missed, a new requirement, the person's instruction) and answer
|
|
394
|
+
the old decision's reasoning; `kb_check` blocks it otherwise. A preference is
|
|
395
|
+
not evidence: propose it instead of superseding. Kibi checks only that a firm
|
|
396
|
+
decision has a reference; never cite words nobody said.
|
|
379
397
|
|
|
380
398
|
Conditional clauses ("only when", "only if", "must not ... unless") compile
|
|
381
399
|
into typed `forbid` rules linked by `requires_rule`, not property facts; one
|
|
@@ -466,7 +484,9 @@ prose (`mode: "requirement"`, or `kb_upsert` with the extended `semantic_text`
|
|
|
466
484
|
and the ledger `mode: "analyze"` returns) and call `mode: "predicates"` again.
|
|
467
485
|
Read `decisionConflicts` and its warnings whenever `plan` is null: they name
|
|
468
486
|
the stored decision facts the candidate would contradict and the requirements
|
|
469
|
-
that own them.
|
|
487
|
+
that own them. To ask what a proposed rule would conflict with, call
|
|
488
|
+
`mode: "predicates"` with its text and no `requirementId`; nothing is written.
|
|
489
|
+
`provide_argument_bindings` and `record_ontology_gap` mean
|
|
470
490
|
the same as for an ungrounded claim, and the gap observation is not a grounding
|
|
471
491
|
link, so write it exactly as returned (tags, `claim_text`, `document.body`, no
|
|
472
492
|
`claim_key`, no relationships). Record an ontology gap only when no returned schema fits the
|
|
@@ -83,7 +83,9 @@ On the first page, intent mode also returns an answer layer in `data.answer`
|
|
|
83
83
|
|
|
84
84
|
- `governing` — current requirements matched by the query or linked to a
|
|
85
85
|
matched entity, each with `via` (how it was reached) and its linked `facts`,
|
|
86
|
-
`scenarios`, `tests`, and `adrs`.
|
|
86
|
+
`scenarios`, `tests`, and `adrs`. A requirement with more linked facts than
|
|
87
|
+
the answer lists carries `moreFacts` (`count` and the `kb_query` `ask` that
|
|
88
|
+
lists them all); never read a short `facts` list as the whole rule.
|
|
87
89
|
- `rationale` — ADRs that explain the decisions.
|
|
88
90
|
- `notGoverning` — superseded or deprecated requirements, with `supersededBy`
|
|
89
91
|
when known. Never read these as current policy; superseded entities are also
|
|
@@ -521,7 +521,7 @@
|
|
|
521
521
|
"default",
|
|
522
522
|
"exploratory"
|
|
523
523
|
],
|
|
524
|
-
"description": "Requirement and ADR only. How firmly the decision was made. firm: a human stated it as a rule; it needs a ref (origin.ref, or approval_ref on a requirement) to their words, and only a human may change it. default
|
|
524
|
+
"description": "Requirement and ADR only. How firmly the decision was made. firm: a human stated it as a rule; it needs a ref (origin.ref, or approval_ref on a requirement) to their words, and only a human may change it. default: a delegated or agent choice; a later agent may supersede it with evidence. exploratory: a flagged guess, expected to be revisited. When absent, it reads as default if an agent wrote the entity (origin.kind agent) and as firm otherwise (a person's, imported or migrated decision); set it explicitly when recording a decision."
|
|
525
525
|
},
|
|
526
526
|
"expects": {
|
|
527
527
|
"type": "string",
|
package/dist/search-answer.d.ts
CHANGED
|
@@ -93,6 +93,14 @@ export type SearchAnswerRequirement = SearchAnswerEntity & Readonly<{
|
|
|
93
93
|
score: number;
|
|
94
94
|
via: string;
|
|
95
95
|
facts: readonly SearchAnswerFact[];
|
|
96
|
+
/**
|
|
97
|
+
* Linked facts the answer left out (over the per-requirement limit or
|
|
98
|
+
* cut to fit the byte budget) and the kb_query that lists them all.
|
|
99
|
+
*/
|
|
100
|
+
moreFacts?: Readonly<{
|
|
101
|
+
count: number;
|
|
102
|
+
ask: string;
|
|
103
|
+
}>;
|
|
96
104
|
scenarios: readonly SearchAnswerEntity[];
|
|
97
105
|
tests: readonly SearchAnswerTest[];
|
|
98
106
|
adrs: readonly SearchAnswerEntity[];
|
|
@@ -140,6 +148,12 @@ export declare const SEARCH_ANSWER_LIMITS: {
|
|
|
140
148
|
readonly seeds: 10;
|
|
141
149
|
readonly governing: 5;
|
|
142
150
|
readonly perRequirement: 4;
|
|
151
|
+
/**
|
|
152
|
+
* Linked facts listed per governing requirement. Facts are what an answer
|
|
153
|
+
* states, so a requirement with several clauses keeps more of them than
|
|
154
|
+
* of its scenarios or tests.
|
|
155
|
+
*/
|
|
156
|
+
readonly factsPerRequirement: 8;
|
|
143
157
|
readonly rationale: 3;
|
|
144
158
|
readonly notGoverning: 5;
|
|
145
159
|
readonly observations: 3;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"search-answer.d.ts","sourceRoot":"","sources":["../src/search-answer.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"search-answer.d.ts","sourceRoot":"","sources":["../src/search-answer.ts"],"names":[],"mappings":"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"}
|
package/dist/search-answer.js
CHANGED
|
@@ -43,6 +43,7 @@ const ROW_KEYS = [
|
|
|
43
43
|
"fact_kind",
|
|
44
44
|
"approved_by",
|
|
45
45
|
"firmness",
|
|
46
|
+
"origin",
|
|
46
47
|
"source",
|
|
47
48
|
"sourceFile",
|
|
48
49
|
"predicate_namespace",
|
|
@@ -64,6 +65,12 @@ export const SEARCH_ANSWER_LIMITS = {
|
|
|
64
65
|
seeds: 10,
|
|
65
66
|
governing: 5,
|
|
66
67
|
perRequirement: 4,
|
|
68
|
+
/**
|
|
69
|
+
* Linked facts listed per governing requirement. Facts are what an answer
|
|
70
|
+
* states, so a requirement with several clauses keeps more of them than
|
|
71
|
+
* of its scenarios or tests.
|
|
72
|
+
*/
|
|
73
|
+
factsPerRequirement: 8,
|
|
67
74
|
rationale: 3,
|
|
68
75
|
notGoverning: 5,
|
|
69
76
|
observations: 3,
|
|
@@ -86,7 +93,7 @@ function unique(ids) {
|
|
|
86
93
|
}
|
|
87
94
|
function brief(entity) {
|
|
88
95
|
const status = text(entity.status);
|
|
89
|
-
const firmness = effectiveFirmness(entity.type, entity.firmness);
|
|
96
|
+
const firmness = effectiveFirmness(entity.type, entity.firmness, entity.origin);
|
|
90
97
|
return {
|
|
91
98
|
id: text(entity.id),
|
|
92
99
|
title: text(entity.title),
|
|
@@ -758,11 +765,19 @@ export async function buildSearchAnswer(prolog, matches, options = {}) {
|
|
|
758
765
|
.map((edge) => edge.from);
|
|
759
766
|
const scenarioIds = unique(from("specified_by"));
|
|
760
767
|
const traversed = firstOf(scenarioIds);
|
|
768
|
+
// A fact the question matched comes first, then the facts that ground a
|
|
769
|
+
// clause (requires_*) before the subject a requirement constrains: the
|
|
770
|
+
// subject's key is already part of each grounding fact's claim.
|
|
771
|
+
const linked = unique(edges
|
|
772
|
+
.filter((edge) => FACT_LINKS.has(edge.rel) && edge.from === req.id)
|
|
773
|
+
.sort((left, right) => factRank(left, seedIds) - factRank(right, seedIds))
|
|
774
|
+
.map((edge) => edge.to));
|
|
775
|
+
if (linked.length > limits.factsPerRequirement)
|
|
776
|
+
truncated = true;
|
|
761
777
|
return {
|
|
762
778
|
req,
|
|
763
|
-
facts:
|
|
764
|
-
|
|
765
|
-
.map((edge) => edge.to)),
|
|
779
|
+
facts: linked.slice(0, limits.factsPerRequirement),
|
|
780
|
+
factsOmitted: Math.max(0, linked.length - limits.factsPerRequirement),
|
|
766
781
|
scenarios: traversed,
|
|
767
782
|
directTests: unique([...from("verified_by"), ...into("validates")]),
|
|
768
783
|
related: firstOf([...from("relates_to"), ...into("relates_to")]),
|
|
@@ -838,6 +853,9 @@ export async function buildSearchAnswer(prolog, matches, options = {}) {
|
|
|
838
853
|
...brief(fact),
|
|
839
854
|
...factDetail(fact, schemas.get(text(fact.id))),
|
|
840
855
|
})),
|
|
856
|
+
...(plan.factsOmitted > 0
|
|
857
|
+
? { moreFacts: moreFactsOf(req.id, plan.factsOmitted) }
|
|
858
|
+
: {}),
|
|
841
859
|
scenarios: rowsOf(plan.scenarios).map(brief),
|
|
842
860
|
tests: rowsOf(testIds[index] ?? []).map((row) => ({
|
|
843
861
|
...brief(row),
|
|
@@ -892,7 +910,14 @@ function answerNote(governingCount, ungoverned) {
|
|
|
892
910
|
const lead = top === undefined
|
|
893
911
|
? ""
|
|
894
912
|
: `The top-ranked match ${top.id} (${top.type}) is linked to no requirement${governingCount === 0 ? "" : "; the governing requirements below were reached through lower-ranked matches"}. `;
|
|
913
|
+
// A fact no requirement links records something seen, not a decision. An
|
|
914
|
+
// agent comparing it with a governing requirement's fact on the same
|
|
915
|
+
// tuple must not weigh the two as equals.
|
|
916
|
+
const ungovernedFact = ungoverned.some((entry) => entry.type === "fact")
|
|
917
|
+
? "A fact in ungoverned is linked to no requirement, so it decides nothing: where it disagrees with a governing requirement's fact, the governing fact holds. "
|
|
918
|
+
: "";
|
|
895
919
|
return (lead +
|
|
920
|
+
ungovernedFact +
|
|
896
921
|
(governingCount === 0
|
|
897
922
|
? "No current requirement matched or owns a matched entity. Absence here is not evidence that nothing governs the change; refine the query or pass sourceLocations."
|
|
898
923
|
: "Governing requirements are current requirements matched by the query or linked to a matched entity. Links are discovery, not proof. A verdict lists the contradiction and scenario-feasibility witnesses that name the requirement; none means no check named it, not that it is proven. Use kb_check and kb_coverage for consistency and proof status."));
|
|
@@ -924,6 +949,17 @@ const ANSWER_TRIM_ORDER = [
|
|
|
924
949
|
"ungoverned",
|
|
925
950
|
"rationale",
|
|
926
951
|
];
|
|
952
|
+
/** Where a linked fact of a governing requirement sorts in its list. */
|
|
953
|
+
function factRank(edge, seedIds) {
|
|
954
|
+
const matched = seedIds.indexOf(edge.to);
|
|
955
|
+
if (matched >= 0)
|
|
956
|
+
return matched;
|
|
957
|
+
return seedIds.length + (edge.rel === "constrains" ? 1 : 0);
|
|
958
|
+
}
|
|
959
|
+
/** The facts an answer left out of a governing requirement, and the ask. */
|
|
960
|
+
function moreFactsOf(requirementId, count) {
|
|
961
|
+
return { count, ask: `kb_query(${JSON.stringify({ id: requirementId })})` };
|
|
962
|
+
}
|
|
927
963
|
const REQUIREMENT_TRIM_ORDER = [
|
|
928
964
|
"unknowns",
|
|
929
965
|
"exceptions",
|
|
@@ -999,7 +1035,17 @@ export function fitSearchAnswer(answer, maxBytes = SEARCH_ANSWER_LIMITS.maxBytes
|
|
|
999
1035
|
if (own) {
|
|
1000
1036
|
current = {
|
|
1001
1037
|
...current,
|
|
1002
|
-
governing: [
|
|
1038
|
+
governing: [
|
|
1039
|
+
{
|
|
1040
|
+
...req,
|
|
1041
|
+
[own]: req[own].slice(0, -1),
|
|
1042
|
+
...(own === "facts"
|
|
1043
|
+
? {
|
|
1044
|
+
moreFacts: moreFactsOf(req.id, (req.moreFacts?.count ?? 0) + 1),
|
|
1045
|
+
}
|
|
1046
|
+
: {}),
|
|
1047
|
+
},
|
|
1048
|
+
],
|
|
1003
1049
|
};
|
|
1004
1050
|
continue;
|
|
1005
1051
|
}
|
|
@@ -14,7 +14,53 @@ export interface GitChangeSnapshot {
|
|
|
14
14
|
/** Reject a changed HEAD or index tree after staged analysis. */
|
|
15
15
|
assertUnchanged(): void;
|
|
16
16
|
inventory: StagedPath[];
|
|
17
|
+
/**
|
|
18
|
+
* Staged merge commits only: paths whose staged content is taken unchanged
|
|
19
|
+
* from a merged parent. They are part of `baseTree`, so the inventory
|
|
20
|
+
* holds only what the merge itself wrote (its conflict resolutions and
|
|
21
|
+
* edits that differ from every parent).
|
|
22
|
+
*/
|
|
23
|
+
mergeInherited?: readonly string[];
|
|
24
|
+
/**
|
|
25
|
+
* Staged snapshots only: knowledge files the commit moves into the
|
|
26
|
+
* canonical `.kb/` layout (for example after `kibi migrate`). `baseTree`
|
|
27
|
+
* holds each source's committed content at its target path, so the
|
|
28
|
+
* inventory shows only what the commit changed inside those files.
|
|
29
|
+
*/
|
|
30
|
+
renameResolved?: ReadonlyArray<{
|
|
31
|
+
from: string;
|
|
32
|
+
to: string;
|
|
33
|
+
}>;
|
|
17
34
|
}
|
|
35
|
+
/**
|
|
36
|
+
* For a staged merge commit, the tree the merge is judged against: HEAD
|
|
37
|
+
* with every path the merge takes unchanged from a merged parent replaced
|
|
38
|
+
* by that staged content. Diffing it against the staged tree leaves only
|
|
39
|
+
* what the merge itself wrote, so debt inherited from the merged branch is
|
|
40
|
+
* not charged to the merge. Null when no merge is in progress or nothing
|
|
41
|
+
* is inherited.
|
|
42
|
+
*/
|
|
43
|
+
export declare function mergeResolutionBase(root: string, baseTree: string, headTree: string, parents: readonly string[]): {
|
|
44
|
+
baseTree: string;
|
|
45
|
+
inherited: string[];
|
|
46
|
+
} | null;
|
|
47
|
+
/**
|
|
48
|
+
* For a staged snapshot, the tree a commit that relocates knowledge files
|
|
49
|
+
* into `.kb/` is judged against: `baseTree` with each relocated file's
|
|
50
|
+
* committed content placed at its new path and the old path removed.
|
|
51
|
+
* Diffing it against the staged tree leaves only the edits the commit made
|
|
52
|
+
* inside those files, so findings that already existed at the old path are
|
|
53
|
+
* not charged to the move. Every other change, including an edit to a file
|
|
54
|
+
* that was already canonical, is diffed as before. Null when nothing is
|
|
55
|
+
* relocated.
|
|
56
|
+
*/
|
|
57
|
+
export declare function renameResolutionBase(root: string, baseTree: string, headTree: string): {
|
|
58
|
+
baseTree: string;
|
|
59
|
+
renames: Array<{
|
|
60
|
+
from: string;
|
|
61
|
+
to: string;
|
|
62
|
+
}>;
|
|
63
|
+
} | null;
|
|
18
64
|
/** Capture one immutable tree from the index and inventory only Git objects. */
|
|
19
65
|
export declare function captureStagedSnapshot(workspaceRoot: string): GitChangeSnapshot;
|
|
20
66
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git-change-snapshot.d.ts","sourceRoot":"","sources":["../../src/traceability/git-change-snapshot.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"git-change-snapshot.d.ts","sourceRoot":"","sources":["../../src/traceability/git-change-snapshot.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAIV,UAAU,EAEX,MAAM,iBAAiB,CAAC;AAKzB,MAAM,MAAM,iBAAiB,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;AAGpE,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,QAAQ,EAAE,MAAM,CAAC;IACjB,0EAA0E;IAC1E,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,gEAAgE;IAChE,OAAO,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC;IACzC,uEAAuE;IACvE,SAAS,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChE,iEAAiE;IACjE,eAAe,IAAI,IAAI,CAAC;IACxB,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC9D;AAueD;;;;;;;GAOG;AAEH,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,SAAS,MAAM,EAAE,GACzB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,EAAE,CAAA;CAAE,GAAG,IAAI,CA6ClD;AAsED;;;;;;;;;GASG;AAEH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE,GAAG,IAAI,CAsB3E;AAED,gFAAgF;AAEhF,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,GACpB,iBAAiB,CAuCnB;AAED;;;;;GAKG;AAEH,wBAAgB,mBAAmB,CACjC,aAAa,EAAE,MAAM,EACrB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,iBAAiB,CAyBnB"}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { execFileSync, spawnSync } from "node:child_process";
|
|
2
|
-
import {
|
|
2
|
+
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import { ENTITY_LANES, isEntityLanePath, isKbKnowledgePath, isSymbolsManifestPath, } from "../utils/kb-paths.js";
|
|
3
6
|
const GIT_EXEC_MAX_BUFFER = 64 * 1024 * 1024;
|
|
4
7
|
function runGit(root, args) {
|
|
5
8
|
try {
|
|
@@ -368,12 +371,188 @@ function snapshotFromTrees(root, baseTree, headTree, headCommit, readGit, assert
|
|
|
368
371
|
inventory: buildInventory(root, baseTree, headTree),
|
|
369
372
|
};
|
|
370
373
|
}
|
|
374
|
+
/** The commits named by MERGE_HEAD while a merge commit is being made. */
|
|
375
|
+
function pendingMergeParents(root) {
|
|
376
|
+
let mergeHeadPath;
|
|
377
|
+
try {
|
|
378
|
+
mergeHeadPath = gitText(root, ["rev-parse", "--git-path", "MERGE_HEAD"]);
|
|
379
|
+
}
|
|
380
|
+
catch {
|
|
381
|
+
return [];
|
|
382
|
+
}
|
|
383
|
+
let text;
|
|
384
|
+
try {
|
|
385
|
+
text = readFileSync(path.resolve(root, mergeHeadPath), "utf8");
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
return [];
|
|
389
|
+
}
|
|
390
|
+
return text
|
|
391
|
+
.split(/\r?\n/)
|
|
392
|
+
.map((line) => line.trim())
|
|
393
|
+
.filter((line) => /^[a-f0-9]{40,64}$/.test(line));
|
|
394
|
+
}
|
|
395
|
+
function changedPaths(root, from, to) {
|
|
396
|
+
return runGit(root, ["diff", "--name-only", "-z", "--no-renames", from, to])
|
|
397
|
+
.toString("utf8")
|
|
398
|
+
.split("\0")
|
|
399
|
+
.filter(Boolean);
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* For a staged merge commit, the tree the merge is judged against: HEAD
|
|
403
|
+
* with every path the merge takes unchanged from a merged parent replaced
|
|
404
|
+
* by that staged content. Diffing it against the staged tree leaves only
|
|
405
|
+
* what the merge itself wrote, so debt inherited from the merged branch is
|
|
406
|
+
* not charged to the merge. Null when no merge is in progress or nothing
|
|
407
|
+
* is inherited.
|
|
408
|
+
*/
|
|
409
|
+
// implements REQ-014
|
|
410
|
+
export function mergeResolutionBase(root, baseTree, headTree, parents) {
|
|
411
|
+
if (parents.length === 0)
|
|
412
|
+
return null;
|
|
413
|
+
const changed = changedPaths(root, baseTree, headTree);
|
|
414
|
+
if (changed.length === 0)
|
|
415
|
+
return null;
|
|
416
|
+
const inherited = new Set();
|
|
417
|
+
for (const parent of parents) {
|
|
418
|
+
const parentTree = treeForCommit(root, parent);
|
|
419
|
+
const differs = new Set(changedPaths(root, parentTree, headTree));
|
|
420
|
+
for (const file of changed) {
|
|
421
|
+
if (!differs.has(file))
|
|
422
|
+
inherited.add(file);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
if (inherited.size === 0)
|
|
426
|
+
return null;
|
|
427
|
+
const paths = [...inherited].sort();
|
|
428
|
+
const listed = runGit(root, [
|
|
429
|
+
"ls-tree",
|
|
430
|
+
"-r",
|
|
431
|
+
"-z",
|
|
432
|
+
"--full-tree",
|
|
433
|
+
headTree,
|
|
434
|
+
"--",
|
|
435
|
+
...paths.map(literalPathspec),
|
|
436
|
+
])
|
|
437
|
+
.toString("utf8")
|
|
438
|
+
.split("\0")
|
|
439
|
+
.filter(Boolean);
|
|
440
|
+
const present = new Set();
|
|
441
|
+
const entries = [];
|
|
442
|
+
for (const row of listed) {
|
|
443
|
+
const tab = row.indexOf("\t");
|
|
444
|
+
if (tab < 0)
|
|
445
|
+
continue;
|
|
446
|
+
const [mode, , oid] = row.slice(0, tab).split(" ");
|
|
447
|
+
const file = row.slice(tab + 1);
|
|
448
|
+
present.add(file);
|
|
449
|
+
entries.push(`${mode} ${oid}\t${file}`);
|
|
450
|
+
}
|
|
451
|
+
const zero = "0".repeat(baseTree.length);
|
|
452
|
+
for (const file of paths) {
|
|
453
|
+
// Deleted on the merged side and absent from the staged tree.
|
|
454
|
+
if (!present.has(file))
|
|
455
|
+
entries.push(`0 ${zero}\t${file}`);
|
|
456
|
+
}
|
|
457
|
+
return {
|
|
458
|
+
baseTree: writeTreeWithEntries(root, baseTree, entries, "kibi-merge-base-"),
|
|
459
|
+
inherited: paths,
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
/** Write `baseTree` with `--index-info` entries applied in a scratch index. */
|
|
463
|
+
function writeTreeWithEntries(root, baseTree, entries, prefix) {
|
|
464
|
+
const scratch = mkdtempSync(path.join(tmpdir(), prefix));
|
|
465
|
+
const env = { ...process.env, GIT_INDEX_FILE: path.join(scratch, "index") };
|
|
466
|
+
try {
|
|
467
|
+
const git = (args, input) => execFileSync("git", [...args], {
|
|
468
|
+
cwd: root,
|
|
469
|
+
env,
|
|
470
|
+
maxBuffer: GIT_EXEC_MAX_BUFFER,
|
|
471
|
+
...(input !== undefined ? { input } : {}),
|
|
472
|
+
stdio: ["pipe", "pipe", "ignore"],
|
|
473
|
+
});
|
|
474
|
+
git(["read-tree", baseTree]);
|
|
475
|
+
git(["update-index", "-z", "--index-info"], `${entries.join("\0")}\0`);
|
|
476
|
+
return git(["write-tree"]).toString("utf8").trim();
|
|
477
|
+
}
|
|
478
|
+
finally {
|
|
479
|
+
rmSync(scratch, { recursive: true, force: true });
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
function renamedPaths(root, from, to) {
|
|
483
|
+
return parseNameStatus(runGit(root, [
|
|
484
|
+
"diff",
|
|
485
|
+
"--name-status",
|
|
486
|
+
"-z",
|
|
487
|
+
"-M",
|
|
488
|
+
"--diff-filter=R",
|
|
489
|
+
from,
|
|
490
|
+
to,
|
|
491
|
+
])).flatMap((row) => row.status === "R" && row.oldPath !== undefined
|
|
492
|
+
? [{ from: row.oldPath, to: row.path }]
|
|
493
|
+
: []);
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* True when `from -> to` moves one knowledge file from outside the canonical
|
|
497
|
+
* layout into the same kind of canonical `.kb/` location: an entity lane
|
|
498
|
+
* file into the same lane, or a symbols manifest / coordinates file onto the
|
|
499
|
+
* canonical file of the same name (`.yml` and `.yaml` alike).
|
|
500
|
+
*/
|
|
501
|
+
function isKnowledgeRelocation(from, to) {
|
|
502
|
+
if (isKbKnowledgePath(from) || !isKbKnowledgePath(to))
|
|
503
|
+
return false;
|
|
504
|
+
if (isSymbolsManifestPath(to)) {
|
|
505
|
+
const stem = (file) => path.posix.basename(file).replace(/\.ya?ml$/, "");
|
|
506
|
+
return stem(from) === stem(to);
|
|
507
|
+
}
|
|
508
|
+
const lane = to.split("/")[1] ?? "";
|
|
509
|
+
return (ENTITY_LANES.includes(lane) &&
|
|
510
|
+
`/${from}`.includes(`/${lane}/`));
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* For a staged snapshot, the tree a commit that relocates knowledge files
|
|
514
|
+
* into `.kb/` is judged against: `baseTree` with each relocated file's
|
|
515
|
+
* committed content placed at its new path and the old path removed.
|
|
516
|
+
* Diffing it against the staged tree leaves only the edits the commit made
|
|
517
|
+
* inside those files, so findings that already existed at the old path are
|
|
518
|
+
* not charged to the move. Every other change, including an edit to a file
|
|
519
|
+
* that was already canonical, is diffed as before. Null when nothing is
|
|
520
|
+
* relocated.
|
|
521
|
+
*/
|
|
522
|
+
// implements REQ-014
|
|
523
|
+
export function renameResolutionBase(root, baseTree, headTree) {
|
|
524
|
+
const zero = "0".repeat(baseTree.length);
|
|
525
|
+
const renames = [];
|
|
526
|
+
const entries = [];
|
|
527
|
+
for (const rename of renamedPaths(root, baseTree, headTree)) {
|
|
528
|
+
if (!isKnowledgeRelocation(rename.from, rename.to))
|
|
529
|
+
continue;
|
|
530
|
+
const source = readTreeEntry(root, baseTree, rename.from);
|
|
531
|
+
if (source?.type !== "blob")
|
|
532
|
+
continue;
|
|
533
|
+
renames.push(rename);
|
|
534
|
+
entries.push(`0 ${zero}\t${rename.from}`);
|
|
535
|
+
entries.push(`${source.mode} ${source.oid}\t${rename.to}`);
|
|
536
|
+
}
|
|
537
|
+
if (renames.length === 0)
|
|
538
|
+
return null;
|
|
539
|
+
return {
|
|
540
|
+
baseTree: writeTreeWithEntries(root, baseTree, entries, "kibi-rename-base-"),
|
|
541
|
+
renames: renames.sort((left, right) => left.to.localeCompare(right.to)),
|
|
542
|
+
};
|
|
543
|
+
}
|
|
371
544
|
/** Capture one immutable tree from the index and inventory only Git objects. */
|
|
372
545
|
// implements REQ-014
|
|
373
546
|
export function captureStagedSnapshot(workspaceRoot) {
|
|
374
547
|
const headCommit = resolveHeadCommit(workspaceRoot);
|
|
375
|
-
const baseTree = treeForCommit(workspaceRoot, headCommit);
|
|
376
548
|
const headTree = gitText(workspaceRoot, ["write-tree"]);
|
|
549
|
+
const commitTree = treeForCommit(workspaceRoot, headCommit);
|
|
550
|
+
const merge = headCommit
|
|
551
|
+
? mergeResolutionBase(workspaceRoot, commitTree, headTree, pendingMergeParents(workspaceRoot))
|
|
552
|
+
: null;
|
|
553
|
+
const mergeTree = merge?.baseTree ?? commitTree;
|
|
554
|
+
const relocation = renameResolutionBase(workspaceRoot, mergeTree, headTree);
|
|
555
|
+
const baseTree = relocation?.baseTree ?? mergeTree;
|
|
377
556
|
const readGit = (args) => translateReadGit(workspaceRoot, args, baseTree, headTree, headCommit);
|
|
378
557
|
const assertUnchanged = () => {
|
|
379
558
|
const currentHead = resolveHeadCommit(workspaceRoot);
|
|
@@ -382,7 +561,12 @@ export function captureStagedSnapshot(workspaceRoot) {
|
|
|
382
561
|
throw new Error("Git index or HEAD changed during staged analysis; retry the operation");
|
|
383
562
|
}
|
|
384
563
|
};
|
|
385
|
-
|
|
564
|
+
const snapshot = snapshotFromTrees(workspaceRoot, baseTree, headTree, headCommit, readGit, assertUnchanged);
|
|
565
|
+
return {
|
|
566
|
+
...snapshot,
|
|
567
|
+
...(merge ? { mergeInherited: merge.inherited } : {}),
|
|
568
|
+
...(relocation ? { renameResolved: relocation.renames } : {}),
|
|
569
|
+
};
|
|
386
570
|
}
|
|
387
571
|
/**
|
|
388
572
|
* Capture changes between explicit revisions. The caller chooses `base`; for
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"staged-diagnostics.d.ts","sourceRoot":"","sources":["../../src/traceability/staged-diagnostics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAGL,KAAK,kBAAkB,EAKxB,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,MAAM,sBAAsB,GAC9B,8BAA8B,GAC9B,wBAAwB,GACxB,8BAA8B,GAC9B,+BAA+B,GAC/B,iCAAiC,GACjC,oCAAoC,GACpC,gCAAgC,GAChC,0BAA0B,GAC1B,2BAA2B,GAC3B,6BAA6B,GAC7B,yBAAyB,GACzB,wCAAwC,GACxC,wBAAwB,CAAC;AAE7B,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D,uDAAuD;IACvD,EAAE,EAAE,sBAAsB,CAAC;IAC3B,QAAQ,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACxC,iEAAiE;IACjE,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,gDAAgD;IAChD,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;
|
|
1
|
+
{"version":3,"file":"staged-diagnostics.d.ts","sourceRoot":"","sources":["../../src/traceability/staged-diagnostics.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAGL,KAAK,kBAAkB,EAKxB,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,MAAM,sBAAsB,GAC9B,8BAA8B,GAC9B,wBAAwB,GACxB,8BAA8B,GAC9B,+BAA+B,GAC/B,iCAAiC,GACjC,oCAAoC,GACpC,gCAAgC,GAChC,0BAA0B,GAC1B,2BAA2B,GAC3B,6BAA6B,GAC7B,yBAAyB,GACzB,wCAAwC,GACxC,wBAAwB,CAAC;AAE7B,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D,uDAAuD;IACvD,EAAE,EAAE,sBAAsB,CAAC;IAC3B,QAAQ,EAAE,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACxC,iEAAiE;IACjE,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IACzB,gDAAgD;IAChD,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACxB,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,0CAA0C;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B;AAsID,wBAAgB,wCAAwC,CACtD,QAAQ,EAAE,kBAAkB,GAC3B,oBAAoB,CAoBtB;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC1C,QAAQ,EAAE,kBAAkB,EAC5B,mBAAmB,GAAE,MAAmC,GACvD,oBAAoB,EAAE,CAiDxB"}
|
|
@@ -8,13 +8,12 @@ function deriveCoordinatesPath(symbolsManifestPath) {
|
|
|
8
8
|
function formatFileList(paths) {
|
|
9
9
|
return paths.join(", ");
|
|
10
10
|
}
|
|
11
|
-
/**
|
|
12
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Every name, in order: the gate output is the list a person works through,
|
|
13
|
+
* so it is never cut short.
|
|
14
|
+
*/
|
|
13
15
|
function formatNameList(names) {
|
|
14
|
-
|
|
15
|
-
const overflow = names.length - shown.length;
|
|
16
|
-
const rendered = shown.join(", ");
|
|
17
|
-
return overflow > 0 ? `${rendered} … and ${overflow} more` : rendered;
|
|
16
|
+
return names.join(", ");
|
|
18
17
|
}
|
|
19
18
|
function symbolsManifestFileDetails(evidence, paths) {
|
|
20
19
|
const pathSet = new Set(paths);
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ExtractionResult } from "../extractors/markdown.js";
|
|
2
|
+
/** A staged requirement whose semantic inventory no longer matches its prose. */
|
|
3
|
+
export declare const STAGED_INVENTORY_DRIFT_RULE = "semantic-inventory-drift";
|
|
4
|
+
export type StagedInventoryDriftViolation = Readonly<{
|
|
5
|
+
rule: typeof STAGED_INVENTORY_DRIFT_RULE;
|
|
6
|
+
entityId: string;
|
|
7
|
+
source: string;
|
|
8
|
+
message: string;
|
|
9
|
+
errors: readonly string[];
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* The staged requirements that declare a semantic inventory contract (now
|
|
13
|
+
* or in the base tree) whose inventory no longer matches their prose. The
|
|
14
|
+
* next `kibi sync` refuses them under the proposition-complete boundary;
|
|
15
|
+
* the gate applies the same test, so drift is caught at the commit that
|
|
16
|
+
* introduces it instead of after a later merge. Requirements without a
|
|
17
|
+
* contract are left to sync, which decides from its own baseline.
|
|
18
|
+
*/
|
|
19
|
+
export declare function stagedInventoryDriftViolations(input: {
|
|
20
|
+
stagedPaths: ReadonlySet<string>;
|
|
21
|
+
snapshotEntities: readonly ExtractionResult[];
|
|
22
|
+
readBase: (path: string) => string | null;
|
|
23
|
+
}): StagedInventoryDriftViolation[];
|
|
24
|
+
//# sourceMappingURL=staged-inventory-drift.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staged-inventory-drift.d.ts","sourceRoot":"","sources":["../../src/traceability/staged-inventory-drift.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAKlE,iFAAiF;AAEjF,eAAO,MAAM,2BAA2B,6BAA6B,CAAC;AAGtE,MAAM,MAAM,6BAA6B,GAAG,QAAQ,CAAC;IACnD,IAAI,EAAE,OAAO,2BAA2B,CAAC;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3B,CAAC,CAAC;AAgCH;;;;;;;GAOG;AAEH,wBAAgB,8BAA8B,CAAC,KAAK,EAAE;IACpD,WAAW,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACjC,gBAAgB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAC9C,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,CAAC;CAC3C,GAAG,6BAA6B,EAAE,CA8BlC"}
|