kibi-cli 2.4.0 → 2.5.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/dist/cli-json-command.d.ts +6 -0
- package/dist/cli-json-command.d.ts.map +1 -1
- package/dist/cli-json-command.js +37 -9
- package/dist/cli-operation-loader.d.ts.map +1 -1
- package/dist/cli-operation-loader.js +7 -0
- package/dist/cli-operation-metadata.d.ts +12 -4
- package/dist/cli-operation-metadata.d.ts.map +1 -1
- package/dist/cli-operation-metadata.js +14 -4
- package/dist/cli-protocol.d.ts +14 -0
- package/dist/cli-protocol.d.ts.map +1 -1
- package/dist/cli-protocol.js +31 -2
- package/dist/cli-register-proof.d.ts.map +1 -1
- package/dist/cli-register-proof.js +13 -0
- package/dist/commands/check.d.ts.map +1 -1
- package/dist/commands/check.js +11 -2
- package/dist/commands/discovery-shared.d.ts.map +1 -1
- package/dist/commands/discovery-shared.js +8 -2
- package/dist/commands/engine.d.ts.map +1 -1
- package/dist/commands/engine.js +4 -2
- package/dist/commands/gc.d.ts.map +1 -1
- package/dist/commands/gc.js +7 -0
- package/dist/commands/init-helpers.d.ts.map +1 -1
- package/dist/commands/init-helpers.js +38 -12
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +10 -15
- package/dist/commands/migrate.d.ts.map +1 -1
- package/dist/commands/migrate.js +281 -14
- package/dist/commands/proof-compact.d.ts +9 -0
- package/dist/commands/proof-compact.d.ts.map +1 -0
- package/dist/commands/proof-compact.js +58 -0
- package/dist/commands/prove.d.ts +38 -0
- package/dist/commands/prove.d.ts.map +1 -1
- package/dist/commands/prove.js +222 -47
- package/dist/commands/sync/persistence.d.ts.map +1 -1
- package/dist/commands/sync/persistence.js +61 -16
- package/dist/commands/sync.d.ts +8 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +42 -16
- package/dist/diagnostics.js +1 -1
- package/dist/engine-limits.d.ts +74 -0
- package/dist/engine-limits.d.ts.map +1 -0
- package/dist/engine-limits.js +201 -0
- package/dist/engine.d.ts +10 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +57 -9
- package/dist/extractors/manifest.d.ts +8 -0
- package/dist/extractors/manifest.d.ts.map +1 -1
- package/dist/extractors/manifest.js +34 -5
- package/dist/extractors/markdown.d.ts +8 -0
- package/dist/extractors/markdown.d.ts.map +1 -1
- package/dist/extractors/markdown.js +57 -0
- package/dist/extractors/relationships.d.ts.map +1 -1
- package/dist/extractors/relationships.js +2 -0
- package/dist/intent-search.d.ts +4 -1
- package/dist/intent-search.d.ts.map +1 -1
- package/dist/intent-search.js +186 -33
- package/dist/operations/bootstrap/candidate-helpers.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidate-helpers.js +8 -1
- package/dist/operations/bootstrap/candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/candidates.js +54 -38
- package/dist/operations/bootstrap/generate.d.ts +2 -0
- package/dist/operations/bootstrap/generate.d.ts.map +1 -1
- package/dist/operations/bootstrap/generate.js +87 -33
- package/dist/operations/bootstrap/intent-claims.d.ts.map +1 -1
- package/dist/operations/bootstrap/intent-claims.js +12 -4
- package/dist/operations/bootstrap/markdown-candidates.d.ts +2 -0
- package/dist/operations/bootstrap/markdown-candidates.d.ts.map +1 -1
- package/dist/operations/bootstrap/markdown-candidates.js +32 -10
- package/dist/operations/bootstrap/presentation.d.ts.map +1 -1
- package/dist/operations/bootstrap/presentation.js +6 -2
- package/dist/operations/bootstrap/requirement-claims.d.ts +1 -0
- package/dist/operations/bootstrap/requirement-claims.d.ts.map +1 -1
- package/dist/operations/bootstrap/requirement-claims.js +13 -1
- package/dist/operations/bootstrap/validation.d.ts +4 -0
- package/dist/operations/bootstrap/validation.d.ts.map +1 -0
- package/dist/operations/bootstrap/validation.js +20 -0
- package/dist/operations/migration/inventory-rederive.d.ts +81 -0
- package/dist/operations/migration/inventory-rederive.d.ts.map +1 -0
- package/dist/operations/migration/inventory-rederive.js +484 -0
- package/dist/operations/migration/kb-sources.d.ts +53 -0
- package/dist/operations/migration/kb-sources.d.ts.map +1 -0
- package/dist/operations/migration/kb-sources.js +233 -0
- package/dist/operations/migration/origin-backfill.d.ts +39 -0
- package/dist/operations/migration/origin-backfill.d.ts.map +1 -0
- package/dist/operations/migration/origin-backfill.js +164 -0
- package/dist/operations/migration/polarity-values.d.ts +10 -0
- package/dist/operations/migration/polarity-values.d.ts.map +1 -0
- package/dist/operations/migration/polarity-values.js +60 -0
- package/dist/operations/migration/schema6.d.ts +59 -0
- package/dist/operations/migration/schema6.d.ts.map +1 -0
- package/dist/operations/migration/schema6.js +379 -0
- package/dist/operations/migration/source-paths.d.ts +131 -0
- package/dist/operations/migration/source-paths.d.ts.map +1 -0
- package/dist/operations/migration/source-paths.js +308 -0
- package/dist/operations/migration/superseded-closure.d.ts +54 -0
- package/dist/operations/migration/superseded-closure.d.ts.map +1 -0
- package/dist/operations/migration/superseded-closure.js +187 -0
- package/dist/operations/modeling/logic-modeling.d.ts.map +1 -1
- package/dist/operations/modeling/logic-modeling.js +3 -5
- package/dist/operations/modeling/model-requirement.d.ts.map +1 -1
- package/dist/operations/modeling/model-requirement.js +225 -67
- package/dist/operations/mutation/contradictions.d.ts +16 -0
- package/dist/operations/mutation/contradictions.d.ts.map +1 -1
- package/dist/operations/mutation/contradictions.js +32 -0
- package/dist/operations/mutation/delete.d.ts.map +1 -1
- package/dist/operations/mutation/delete.js +15 -7
- package/dist/operations/mutation/origin.d.ts +21 -0
- package/dist/operations/mutation/origin.d.ts.map +1 -0
- package/dist/operations/mutation/origin.js +78 -0
- package/dist/operations/mutation/plan-apply-journal.d.ts +182 -0
- package/dist/operations/mutation/plan-apply-journal.d.ts.map +1 -0
- package/dist/operations/mutation/plan-apply-journal.js +613 -0
- package/dist/operations/mutation/predicate-vocabulary-guard.d.ts +3 -1
- package/dist/operations/mutation/predicate-vocabulary-guard.d.ts.map +1 -1
- package/dist/operations/mutation/predicate-vocabulary-guard.js +13 -2
- package/dist/operations/mutation/relationships.d.ts +5 -5
- package/dist/operations/mutation/relationships.d.ts.map +1 -1
- package/dist/operations/mutation/relationships.js +31 -11
- package/dist/operations/mutation/serialization.d.ts.map +1 -1
- package/dist/operations/mutation/serialization.js +3 -1
- package/dist/operations/mutation/source-authoring.d.ts +6 -0
- package/dist/operations/mutation/source-authoring.d.ts.map +1 -1
- package/dist/operations/mutation/source-authoring.js +7 -1
- package/dist/operations/mutation/types.d.ts +14 -0
- package/dist/operations/mutation/types.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.d.ts +30 -3
- package/dist/operations/mutation/upsert.d.ts.map +1 -1
- package/dist/operations/mutation/upsert.js +105 -35
- package/dist/operations/mutation/validate-upsert.d.ts +6 -0
- package/dist/operations/mutation/validate-upsert.d.ts.map +1 -1
- package/dist/operations/mutation/validate-upsert.js +34 -30
- package/dist/operations/planning/apply-plan.d.ts.map +1 -1
- package/dist/operations/planning/apply-plan.js +753 -145
- package/dist/operations/planning/compile-intent.d.ts +34 -1
- package/dist/operations/planning/compile-intent.d.ts.map +1 -1
- package/dist/operations/planning/compile-intent.js +314 -98
- package/dist/operations/proof/code-scope.d.ts +28 -0
- package/dist/operations/proof/code-scope.d.ts.map +1 -1
- package/dist/operations/proof/code-scope.js +72 -0
- package/dist/operations/proof/compact-receipts.d.ts +49 -0
- package/dist/operations/proof/compact-receipts.d.ts.map +1 -0
- package/dist/operations/proof/compact-receipts.js +160 -0
- package/dist/operations/proof/ingest-proof.d.ts +2 -0
- package/dist/operations/proof/ingest-proof.d.ts.map +1 -1
- package/dist/operations/proof/ingest-proof.js +44 -23
- package/dist/operations/proof/prune-receipts.d.ts.map +1 -1
- package/dist/operations/proof/prune-receipts.js +5 -9
- package/dist/operations/proof/receipt-compaction.d.ts +48 -0
- package/dist/operations/proof/receipt-compaction.d.ts.map +1 -0
- package/dist/operations/proof/receipt-compaction.js +121 -0
- package/dist/operations/semantic-advisor/analysis-receipt.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analysis-receipt.js +12 -1
- package/dist/operations/semantic-advisor/analyze-prose.d.ts +2 -1
- package/dist/operations/semantic-advisor/analyze-prose.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/analyze-prose.js +51 -5
- package/dist/operations/semantic-advisor/clauses.d.ts +1 -0
- package/dist/operations/semantic-advisor/clauses.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/clauses.js +11 -1
- package/dist/operations/semantic-advisor/conditional-rules.d.ts +33 -0
- package/dist/operations/semantic-advisor/conditional-rules.d.ts.map +1 -0
- package/dist/operations/semantic-advisor/conditional-rules.js +262 -0
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts +3 -1
- package/dist/operations/semantic-advisor/ingestion-boundary.d.ts.map +1 -1
- package/dist/operations/semantic-advisor/ingestion-boundary.js +14 -6
- package/dist/operations/semantic-advisor/plugin-orchestration.js +1 -1
- package/dist/prolog/codec.d.ts.map +1 -1
- package/dist/prolog/codec.js +2 -1
- package/dist/prolog.d.ts +9 -0
- package/dist/prolog.d.ts.map +1 -1
- package/dist/prolog.js +56 -10
- package/dist/proof/command-test-report.d.ts +74 -0
- package/dist/proof/command-test-report.d.ts.map +1 -0
- package/dist/proof/command-test-report.js +206 -0
- package/dist/public/branch-resolver.d.ts +1 -0
- package/dist/public/branch-resolver.d.ts.map +1 -1
- package/dist/public/branch-resolver.js +1 -0
- package/dist/public/entity-origin.d.ts +69 -0
- package/dist/public/entity-origin.d.ts.map +1 -0
- package/dist/public/entity-origin.js +142 -0
- package/dist/public/impact/full-kb-quality.d.ts.map +1 -1
- package/dist/public/impact/full-kb-quality.js +1 -0
- package/dist/public/impact/requirement-quality.js +1 -1
- package/dist/public/operations/catalog.d.ts +130 -19
- package/dist/public/operations/catalog.d.ts.map +1 -1
- package/dist/public/operations/catalog.js +3 -0
- package/dist/public/operations/check-executor.d.ts.map +1 -1
- package/dist/public/operations/check-executor.js +8 -0
- package/dist/public/operations/contracts.d.ts +0 -5
- package/dist/public/operations/contracts.d.ts.map +1 -1
- package/dist/public/operations/contracts.js +63 -14
- package/dist/public/operations/discovery-entities.d.ts +15 -0
- package/dist/public/operations/discovery-entities.d.ts.map +1 -1
- package/dist/public/operations/discovery-entities.js +59 -0
- package/dist/public/operations/discovery-executors.d.ts +6 -1
- package/dist/public/operations/discovery-executors.d.ts.map +1 -1
- package/dist/public/operations/discovery-executors.js +65 -6
- package/dist/public/operations/index.d.ts +1 -0
- package/dist/public/operations/index.d.ts.map +1 -1
- package/dist/public/operations/index.js +1 -0
- package/dist/public/operations/migration-plan.d.ts +5 -0
- package/dist/public/operations/migration-plan.d.ts.map +1 -1
- package/dist/public/operations/migration-plan.js +26 -1
- package/dist/public/operations/node-ports.d.ts.map +1 -1
- package/dist/public/operations/node-ports.js +24 -3
- package/dist/public/operations/origin-review.d.ts +51 -0
- package/dist/public/operations/origin-review.d.ts.map +1 -0
- package/dist/public/operations/origin-review.js +307 -0
- package/dist/public/operations/predicate-schema-conformance.js +1 -1
- package/dist/public/operations/repair-plan.d.ts.map +1 -1
- package/dist/public/operations/repair-plan.js +4 -0
- package/dist/public/operations/result-envelope.d.ts.map +1 -1
- package/dist/public/operations/result-envelope.js +17 -5
- package/dist/public/operations/runtime-types.d.ts +9 -0
- package/dist/public/operations/runtime-types.d.ts.map +1 -1
- package/dist/public/operations/schema6-check-actions.d.ts +127 -0
- package/dist/public/operations/schema6-check-actions.d.ts.map +1 -0
- package/dist/public/operations/schema6-check-actions.js +575 -0
- package/dist/public/operations/source-path-dangling.d.ts +17 -0
- package/dist/public/operations/source-path-dangling.d.ts.map +1 -0
- package/dist/public/operations/source-path-dangling.js +66 -0
- package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
- package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
- package/dist/public/operations/specs/check-rules.generated.js +15 -1
- package/dist/public/operations/specs/check.d.ts +2 -2
- package/dist/public/operations/specs/check.js +1 -1
- package/dist/public/operations/specs/composite.d.ts +351 -0
- package/dist/public/operations/specs/composite.d.ts.map +1 -0
- package/dist/public/operations/specs/composite.js +96 -0
- package/dist/public/operations/specs/discovery.d.ts +8 -3
- package/dist/public/operations/specs/discovery.d.ts.map +1 -1
- package/dist/public/operations/specs/discovery.js +8 -3
- package/dist/public/operations/specs/modeling.d.ts +2 -2
- package/dist/public/operations/specs/modeling.js +2 -2
- package/dist/public/operations/specs/mutation-schemas.d.ts +73 -8
- package/dist/public/operations/specs/mutation-schemas.d.ts.map +1 -1
- package/dist/public/operations/specs/mutation-schemas.js +43 -7
- package/dist/public/operations/specs/mutation.d.ts +1 -1
- package/dist/public/operations/specs/mutation.js +1 -1
- package/dist/public/operations/specs/planning.d.ts +2 -2
- package/dist/public/operations/specs/planning.js +4 -4
- package/dist/public/operations/specs/reporting.d.ts.map +1 -1
- package/dist/public/operations/specs/reporting.js +13 -26
- package/dist/public/operations/specs/upsert.d.ts +79 -9
- package/dist/public/operations/specs/upsert.d.ts.map +1 -1
- package/dist/public/operations/specs/upsert.js +6 -1
- package/dist/public/operations/types.d.ts +1 -1
- package/dist/public/operations/types.d.ts.map +1 -1
- package/dist/public/proof-receipt.d.ts +1 -0
- package/dist/public/proof-receipt.d.ts.map +1 -1
- package/dist/public/schemas/entity.d.ts.map +1 -1
- package/dist/public/schemas/entity.js +52 -0
- package/dist/public/schemas/relationship.d.ts.map +1 -1
- package/dist/public/schemas/relationship.js +2 -0
- package/dist/public/skills/kibi-bootstrap/SKILL.md +35 -67
- package/dist/public/skills/kibi-bootstrap/resources/bootstrap.md +6 -0
- package/dist/public/skills/kibi-usage/SKILL.md +68 -18
- package/dist/public/skills/kibi-usage/resources/fact-lanes.md +5 -5
- package/dist/public/skills/kibi-usage/resources/kb-improvement.md +1 -1
- package/dist/public/skills/kibi-usage/resources/logic-ir.md +2 -2
- package/dist/public/skills/kibi-usage/resources/operation-access.md +25 -1
- package/dist/public/skills/kibi-usage/resources/ui-requirements.md +4 -4
- package/dist/public/skills/kibi-usage/resources/workflows.md +42 -25
- package/dist/public/telemetry-acceptance.d.ts +58 -2
- package/dist/public/telemetry-acceptance.d.ts.map +1 -1
- package/dist/public/telemetry-acceptance.js +136 -10
- package/dist/public/telemetry-remediation.d.ts.map +1 -1
- package/dist/public/telemetry-remediation.js +26 -10
- package/dist/relationships/shards.d.ts +13 -0
- package/dist/relationships/shards.d.ts.map +1 -1
- package/dist/relationships/shards.js +54 -28
- package/dist/runtime/cli-runtime.d.ts.map +1 -1
- package/dist/runtime/cli-runtime.js +44 -3
- package/dist/runtime/detached-snapshot.d.ts +38 -0
- package/dist/runtime/detached-snapshot.d.ts.map +1 -0
- package/dist/runtime/detached-snapshot.js +92 -0
- package/dist/schemas/entity.schema.json +122 -0
- package/dist/search-answer.d.ts +157 -0
- package/dist/search-answer.d.ts.map +1 -0
- package/dist/search-answer.js +846 -0
- package/dist/traceability/impact-knowledge.d.ts.map +1 -1
- package/dist/traceability/impact-knowledge.js +7 -0
- package/dist/traceability/symbol-extract.js +3 -3
- package/dist/traceability/temp-kb.d.ts.map +1 -1
- package/dist/traceability/temp-kb.js +12 -0
- package/dist/types/entities.d.ts +13 -0
- package/dist/types/entities.d.ts.map +1 -1
- package/dist/types/relationships.d.ts +1 -1
- package/dist/types/relationships.d.ts.map +1 -1
- package/dist/utils/branch-resolver.d.ts +37 -1
- package/dist/utils/branch-resolver.d.ts.map +1 -1
- package/dist/utils/branch-resolver.js +130 -3
- package/dist/utils/repo-relative-path.d.ts +18 -0
- package/dist/utils/repo-relative-path.d.ts.map +1 -0
- package/dist/utils/repo-relative-path.js +58 -0
- package/dist/utils/rule-registry.generated.d.ts +75 -3
- package/dist/utils/rule-registry.generated.d.ts.map +1 -1
- package/dist/utils/rule-registry.generated.js +89 -3
- 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 +4 -3
- package/dist/utils/strict-modeling.d.ts +1 -1
- package/dist/utils/strict-modeling.d.ts.map +1 -1
- package/dist/utils/strict-modeling.js +23 -3
- package/package.json +3 -3
- package/schema/entities.pl +22 -0
- package/schema/relationships.pl +14 -0
- package/schema/validation.pl +45 -1
- package/src/public/branch-resolver.ts +1 -0
- package/src/public/entity-origin.ts +175 -0
- package/src/public/impact/full-kb-quality.ts +1 -0
- package/src/public/impact/requirement-quality.ts +1 -1
- package/src/public/operations/catalog.ts +3 -0
- package/src/public/operations/check-executor.ts +15 -0
- package/src/public/operations/contracts.ts +75 -15
- package/src/public/operations/discovery-entities.ts +74 -0
- package/src/public/operations/discovery-executors.ts +88 -10
- package/src/public/operations/index.ts +1 -0
- package/src/public/operations/migration-plan.ts +30 -1
- package/src/public/operations/node-ports.ts +24 -3
- package/src/public/operations/origin-review.ts +375 -0
- package/src/public/operations/predicate-schema-conformance.ts +1 -1
- package/src/public/operations/repair-plan.ts +4 -0
- package/src/public/operations/result-envelope.ts +18 -6
- package/src/public/operations/runtime-types.ts +9 -0
- package/src/public/operations/schema6-check-actions.ts +699 -0
- package/src/public/operations/source-path-dangling.ts +81 -0
- package/src/public/operations/specs/check-rules.generated.ts +15 -1
- package/src/public/operations/specs/check.ts +1 -1
- package/src/public/operations/specs/composite.ts +141 -0
- package/src/public/operations/specs/discovery.ts +9 -3
- package/src/public/operations/specs/modeling.ts +2 -2
- package/src/public/operations/specs/mutation-schemas.ts +49 -7
- package/src/public/operations/specs/mutation.ts +1 -1
- package/src/public/operations/specs/planning.ts +4 -4
- package/src/public/operations/specs/reporting.ts +13 -38
- package/src/public/operations/specs/upsert.ts +7 -1
- package/src/public/operations/types.ts +2 -0
- package/src/public/proof-receipt.ts +1 -0
- package/src/public/schemas/entity.ts +57 -0
- package/src/public/schemas/relationship.ts +2 -0
- package/src/public/skills/kibi-bootstrap/SKILL.md +35 -67
- package/src/public/skills/kibi-bootstrap/resources/bootstrap.md +6 -0
- package/src/public/skills/kibi-usage/SKILL.md +68 -18
- package/src/public/skills/kibi-usage/resources/fact-lanes.md +5 -5
- package/src/public/skills/kibi-usage/resources/kb-improvement.md +1 -1
- package/src/public/skills/kibi-usage/resources/logic-ir.md +2 -2
- package/src/public/skills/kibi-usage/resources/operation-access.md +25 -1
- package/src/public/skills/kibi-usage/resources/ui-requirements.md +4 -4
- package/src/public/skills/kibi-usage/resources/workflows.md +42 -25
- package/src/public/telemetry-acceptance-types.d.ts +4 -1
- package/src/public/telemetry-acceptance.ts +204 -10
- package/src/public/telemetry-remediation.ts +39 -10
- package/src/schemas/entity.schema.json +122 -0
- package/src/schemas/relationship.schema.json +2 -0
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Kibi — repo-local, per-branch, queryable long-term memory for software projects
|
|
3
|
+
Copyright (C) 2026 Piotr Franczyk
|
|
4
|
+
|
|
5
|
+
This program is free software: you can redistribute it and/or modify
|
|
6
|
+
it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
(at your option) any later version.
|
|
9
|
+
|
|
10
|
+
This program is distributed in the hope that it will be useful,
|
|
11
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
GNU Affero General Public License for more details.
|
|
14
|
+
|
|
15
|
+
You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
import { createHash } from "node:crypto";
|
|
19
|
+
import path from "node:path";
|
|
20
|
+
import { isDeepStrictEqual } from "node:util";
|
|
21
|
+
import { load as loadYaml } from "js-yaml";
|
|
22
|
+
import { parseDocument } from "yaml";
|
|
23
|
+
import { extractFromMarkdown, extractFromMarkdownString, } from "../../extractors/markdown.js";
|
|
24
|
+
import { readAllShards } from "../../relationships/shards.js";
|
|
25
|
+
import { KB_PATHS } from "../../utils/kb-paths.js";
|
|
26
|
+
import { analyzeSemanticAdvisorInput } from "../semantic-advisor/analyze-prose.js";
|
|
27
|
+
import { validateSemanticInventoryBoundary } from "../semantic-advisor/ingestion-boundary.js";
|
|
28
|
+
import { SEMANTIC_INVENTORY_VERSION, semanticSourceOf, } from "../semantic-advisor/shared.js";
|
|
29
|
+
import { listLaneMarkdownFiles, readText, sliceFrontmatter, writeFileAtomically, } from "./kb-sources.js";
|
|
30
|
+
/**
|
|
31
|
+
* Re-derive a requirement's stored semantic inventory with the current
|
|
32
|
+
* semantic advisor.
|
|
33
|
+
*
|
|
34
|
+
* An advisor upgrade can split or classify prose differently than the
|
|
35
|
+
* version that wrote a requirement's inventory, and proposition-complete
|
|
36
|
+
* ingestion then rejects the requirement on sync. Re-derivation keeps what
|
|
37
|
+
* the author established and never invents logic:
|
|
38
|
+
*
|
|
39
|
+
* - a claim whose claim_key and claim_text still match keeps its status, so
|
|
40
|
+
* a `modeled` claim stays modeled and its grounding links still apply;
|
|
41
|
+
* - a new or changed claim is unresolved (the advisor's own non-modeled
|
|
42
|
+
* status, `missing` when the advisor would call it modeled), never
|
|
43
|
+
* `modeled`;
|
|
44
|
+
* - roles and spans follow the current advisor; logic_claims lists exactly
|
|
45
|
+
* the assertive claims; semantic_source_hash is recomputed from the prose.
|
|
46
|
+
*
|
|
47
|
+
* Re-derivation is unsafe, and left to a person, when a modeled claim would
|
|
48
|
+
* disappear or turn into context while a logical grounding link still points
|
|
49
|
+
* at it, or when the result would still fail ingestion.
|
|
50
|
+
*/
|
|
51
|
+
const CONTEXT_ROLES = new Set(["rationale", "example", "subjective"]);
|
|
52
|
+
const GROUNDING_RELATIONSHIPS = new Set([
|
|
53
|
+
"requires_property",
|
|
54
|
+
"requires_predicate",
|
|
55
|
+
"requires_rule",
|
|
56
|
+
]);
|
|
57
|
+
const UNRESOLVED_STATUSES = new Set(["ambiguous", "ontology_gap", "missing"]);
|
|
58
|
+
function isRecord(value) {
|
|
59
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
60
|
+
}
|
|
61
|
+
function text(value) {
|
|
62
|
+
return typeof value === "string" ? value : "";
|
|
63
|
+
}
|
|
64
|
+
function canonicalJson(value) {
|
|
65
|
+
if (Array.isArray(value))
|
|
66
|
+
return `[${value.map(canonicalJson).join(",")}]`;
|
|
67
|
+
if (isRecord(value)) {
|
|
68
|
+
return `{${Object.keys(value)
|
|
69
|
+
.sort()
|
|
70
|
+
.map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`)
|
|
71
|
+
.join(",")}}`;
|
|
72
|
+
}
|
|
73
|
+
return JSON.stringify(value);
|
|
74
|
+
}
|
|
75
|
+
function storedInventory(entity) {
|
|
76
|
+
const raw = entity.semantic_inventory;
|
|
77
|
+
if (!Array.isArray(raw))
|
|
78
|
+
return [];
|
|
79
|
+
return raw.filter(isRecord).map((entry) => {
|
|
80
|
+
const span = isRecord(entry.span) ? entry.span : {};
|
|
81
|
+
return {
|
|
82
|
+
claim_key: text(entry.claim_key),
|
|
83
|
+
claim_text: text(entry.claim_text),
|
|
84
|
+
role: text(entry.role),
|
|
85
|
+
status: text(entry.status),
|
|
86
|
+
span: {
|
|
87
|
+
start: typeof span.start === "number" ? span.start : -1,
|
|
88
|
+
end: typeof span.end === "number" ? span.end : -1,
|
|
89
|
+
},
|
|
90
|
+
...(typeof entry.semantic_key === "string"
|
|
91
|
+
? { semantic_key: entry.semantic_key }
|
|
92
|
+
: {}),
|
|
93
|
+
...(typeof entry.reason === "string" ? { reason: entry.reason } : {}),
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
function advertisesContract(entity) {
|
|
98
|
+
return (entity.semantic_inventory_version !== undefined ||
|
|
99
|
+
entity.semantic_source_hash !== undefined ||
|
|
100
|
+
entity.semantic_inventory !== undefined);
|
|
101
|
+
}
|
|
102
|
+
/** Lazily resolves grounding fact ids to their claim_key. */
|
|
103
|
+
class FactClaimIndex {
|
|
104
|
+
workspaceRoot;
|
|
105
|
+
byId;
|
|
106
|
+
constructor(workspaceRoot) {
|
|
107
|
+
this.workspaceRoot = workspaceRoot;
|
|
108
|
+
}
|
|
109
|
+
claimKey(factId) {
|
|
110
|
+
const direct = path.join(this.workspaceRoot, KB_PATHS.lanes.facts, `${factId}.md`);
|
|
111
|
+
try {
|
|
112
|
+
const result = extractFromMarkdown(direct);
|
|
113
|
+
if (result.entity.id === factId)
|
|
114
|
+
return result.entity.claim_key;
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Fall back to the full index: the file stem may differ from the id.
|
|
118
|
+
}
|
|
119
|
+
if (this.byId === undefined) {
|
|
120
|
+
this.byId = new Map();
|
|
121
|
+
for (const file of listLaneMarkdownFiles(this.workspaceRoot, ["facts"])) {
|
|
122
|
+
try {
|
|
123
|
+
const { entity } = extractFromMarkdown(file.absolutePath);
|
|
124
|
+
if (entity.claim_key !== undefined) {
|
|
125
|
+
this.byId.set(entity.id, entity.claim_key);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Unreadable facts are reported by sync, not here.
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return this.byId.get(factId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function relationshipsFor(id, extracted, shards) {
|
|
137
|
+
const unique = new Map();
|
|
138
|
+
for (const relationship of [...extracted, ...shards]) {
|
|
139
|
+
if (relationship.from !== id)
|
|
140
|
+
continue;
|
|
141
|
+
unique.set(`${relationship.type}\u0000${relationship.from}\u0000${relationship.to}`, relationship);
|
|
142
|
+
}
|
|
143
|
+
return [...unique.values()];
|
|
144
|
+
}
|
|
145
|
+
function unresolvedStatus(proposition) {
|
|
146
|
+
return UNRESOLVED_STATUSES.has(proposition.status)
|
|
147
|
+
? proposition.status
|
|
148
|
+
: "missing";
|
|
149
|
+
}
|
|
150
|
+
function rederive(stored, propositions) {
|
|
151
|
+
const storedByKey = new Map(stored.map((entry) => [entry.claim_key, entry]));
|
|
152
|
+
const carried = new Set();
|
|
153
|
+
const inventory = [];
|
|
154
|
+
const changes = [];
|
|
155
|
+
const modeledBecameContext = [];
|
|
156
|
+
for (const proposition of propositions) {
|
|
157
|
+
const candidate = storedByKey.get(proposition.claim_key);
|
|
158
|
+
const previous = candidate !== undefined && candidate.claim_text === proposition.claim_text
|
|
159
|
+
? candidate
|
|
160
|
+
: undefined;
|
|
161
|
+
const context = CONTEXT_ROLES.has(proposition.role);
|
|
162
|
+
let status;
|
|
163
|
+
let change;
|
|
164
|
+
if (previous === undefined) {
|
|
165
|
+
status = context ? "nonlogical" : unresolvedStatus(proposition);
|
|
166
|
+
change = context ? "new_context" : "new_unresolved";
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
carried.add(previous.claim_key);
|
|
170
|
+
if (context) {
|
|
171
|
+
status = "nonlogical";
|
|
172
|
+
if (previous.status === "modeled") {
|
|
173
|
+
modeledBecameContext.push(previous.claim_key);
|
|
174
|
+
}
|
|
175
|
+
change = previous.status === "nonlogical" ? "kept" : "now_context";
|
|
176
|
+
}
|
|
177
|
+
else if (previous.status === "nonlogical") {
|
|
178
|
+
status = unresolvedStatus(proposition);
|
|
179
|
+
change = "now_unresolved";
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
status = previous.status;
|
|
183
|
+
change = "kept";
|
|
184
|
+
}
|
|
185
|
+
if (change === "kept" && previous.role !== proposition.role) {
|
|
186
|
+
change = "role_changed";
|
|
187
|
+
}
|
|
188
|
+
else if (change === "kept" &&
|
|
189
|
+
(previous.span.start !== proposition.span.start ||
|
|
190
|
+
previous.span.end !== proposition.span.end)) {
|
|
191
|
+
change = "span_changed";
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const keepsStatus = previous !== undefined && previous.status === status;
|
|
195
|
+
const reason = keepsStatus ? previous?.reason : proposition.reason;
|
|
196
|
+
inventory.push({
|
|
197
|
+
claim_key: proposition.claim_key,
|
|
198
|
+
claim_text: proposition.claim_text,
|
|
199
|
+
role: proposition.role,
|
|
200
|
+
status,
|
|
201
|
+
span: { start: proposition.span.start, end: proposition.span.end },
|
|
202
|
+
...(keepsStatus && status === "modeled" && previous?.semantic_key
|
|
203
|
+
? { semantic_key: previous.semantic_key }
|
|
204
|
+
: {}),
|
|
205
|
+
...(status !== "modeled" && reason !== undefined ? { reason } : {}),
|
|
206
|
+
});
|
|
207
|
+
changes.push({
|
|
208
|
+
claim_key: proposition.claim_key,
|
|
209
|
+
change,
|
|
210
|
+
...(previous !== undefined
|
|
211
|
+
? { before: { role: previous.role, status: previous.status } }
|
|
212
|
+
: {}),
|
|
213
|
+
after: { role: proposition.role, status },
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
for (const entry of stored) {
|
|
217
|
+
if (carried.has(entry.claim_key))
|
|
218
|
+
continue;
|
|
219
|
+
changes.push({
|
|
220
|
+
claim_key: entry.claim_key,
|
|
221
|
+
change: "dropped",
|
|
222
|
+
before: { role: entry.role, status: entry.status },
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
return { inventory, changes, modeledBecameContext };
|
|
226
|
+
}
|
|
227
|
+
function summarize(changes, inventory) {
|
|
228
|
+
return {
|
|
229
|
+
keptModeled: inventory.filter((entry) => entry.status === "modeled").length,
|
|
230
|
+
roleChanges: changes.filter((change) => change.before !== undefined &&
|
|
231
|
+
change.after !== undefined &&
|
|
232
|
+
change.before.role !== change.after.role).length,
|
|
233
|
+
newlyUnresolved: changes.filter((change) => change.change === "new_unresolved" ||
|
|
234
|
+
change.change === "now_unresolved").length,
|
|
235
|
+
droppedClaims: changes.filter((change) => change.change === "dropped")
|
|
236
|
+
.length,
|
|
237
|
+
downgradedModeled: changes.filter((change) => change.before?.status === "modeled" &&
|
|
238
|
+
change.after?.status !== "modeled").length,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
function planOne(workspaceRoot, relativePath, entity, extracted, shards, facts) {
|
|
242
|
+
if (entity.type !== "req" || !advertisesContract(entity))
|
|
243
|
+
return null;
|
|
244
|
+
const relationships = relationshipsFor(entity.id, extracted, shards);
|
|
245
|
+
const payload = {
|
|
246
|
+
type: entity.type,
|
|
247
|
+
id: entity.id,
|
|
248
|
+
properties: entity,
|
|
249
|
+
relationships,
|
|
250
|
+
};
|
|
251
|
+
const receipt = analyzeSemanticAdvisorInput({ payload }).receipt;
|
|
252
|
+
const before = validateSemanticInventoryBoundary(payload, relationships, receipt);
|
|
253
|
+
if (!before.applicable || before.errors.length === 0)
|
|
254
|
+
return null;
|
|
255
|
+
const stored = storedInventory(entity);
|
|
256
|
+
const { inventory, changes, modeledBecameContext } = rederive(stored, receipt.propositions);
|
|
257
|
+
const contract = {
|
|
258
|
+
semantic_inventory_version: SEMANTIC_INVENTORY_VERSION,
|
|
259
|
+
semantic_source_field: semanticSourceOf(payload).field,
|
|
260
|
+
semantic_source_hash: before.sourceHash,
|
|
261
|
+
semantic_inventory: inventory,
|
|
262
|
+
logic_claims: inventory
|
|
263
|
+
.filter((entry) => !CONTEXT_ROLES.has(entry.role))
|
|
264
|
+
.map((entry) => entry.claim_key),
|
|
265
|
+
};
|
|
266
|
+
const reasons = [];
|
|
267
|
+
for (const claimKey of modeledBecameContext) {
|
|
268
|
+
reasons.push(`modeled claim ${claimKey} is now classified as context (${inventory.find((entry) => entry.claim_key === claimKey)?.role ?? "context"}); its grounding cannot stay`);
|
|
269
|
+
}
|
|
270
|
+
const groundingKeys = [];
|
|
271
|
+
for (const relationship of relationships) {
|
|
272
|
+
if (!GROUNDING_RELATIONSHIPS.has(relationship.type))
|
|
273
|
+
continue;
|
|
274
|
+
const claimKey = facts.claimKey(relationship.to);
|
|
275
|
+
if (claimKey === undefined) {
|
|
276
|
+
reasons.push(`grounding target ${relationship.to} (${relationship.type}) declares no claim_key`);
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
groundingKeys.push(claimKey);
|
|
280
|
+
}
|
|
281
|
+
const modeledKeys = inventory
|
|
282
|
+
.filter((entry) => entry.status === "modeled")
|
|
283
|
+
.map((entry) => entry.claim_key);
|
|
284
|
+
for (const claimKey of new Set(groundingKeys)) {
|
|
285
|
+
if (modeledKeys.includes(claimKey))
|
|
286
|
+
continue;
|
|
287
|
+
const dropped = changes.find((change) => change.claim_key === claimKey && change.change === "dropped");
|
|
288
|
+
reasons.push(dropped !== undefined
|
|
289
|
+
? `grounded claim ${claimKey} no longer exists in the current advisor's inventory`
|
|
290
|
+
: `grounded claim ${claimKey} is not a modeled claim of the re-derived inventory`);
|
|
291
|
+
}
|
|
292
|
+
const nextProperties = {
|
|
293
|
+
...entity,
|
|
294
|
+
...contract,
|
|
295
|
+
};
|
|
296
|
+
const nextPayload = { ...payload, properties: nextProperties };
|
|
297
|
+
const after = validateSemanticInventoryBoundary(nextPayload, relationships, analyzeSemanticAdvisorInput({ payload: nextPayload }).receipt);
|
|
298
|
+
for (const error of after.errors) {
|
|
299
|
+
reasons.push(`re-derived inventory would still fail ingestion: ${error}`);
|
|
300
|
+
}
|
|
301
|
+
return {
|
|
302
|
+
requirementId: entity.id,
|
|
303
|
+
path: relativePath,
|
|
304
|
+
errors: before.errors,
|
|
305
|
+
safe: reasons.length === 0,
|
|
306
|
+
reasons: [...new Set(reasons)],
|
|
307
|
+
summary: summarize(changes, inventory),
|
|
308
|
+
changes,
|
|
309
|
+
contract,
|
|
310
|
+
contractHash: createHash("sha256")
|
|
311
|
+
.update(canonicalJson(contract))
|
|
312
|
+
.digest("hex"),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
function readShardRelationships(workspaceRoot) {
|
|
316
|
+
try {
|
|
317
|
+
return readAllShards(path.join(workspaceRoot, ".kb")).map(({ type, from, to }) => ({ type, from, to }));
|
|
318
|
+
}
|
|
319
|
+
catch {
|
|
320
|
+
// Malformed shards fail sync with their own diagnostic.
|
|
321
|
+
return [];
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* Every current requirement whose stored inventory contract no longer matches
|
|
326
|
+
* the current semantic advisor, with its re-derived contract. Read-only;
|
|
327
|
+
* reports all of them instead of stopping at the first. `onlyId` limits the
|
|
328
|
+
* scan to one requirement.
|
|
329
|
+
*/
|
|
330
|
+
// implements REQ-kibi-proposition-complete-ingestion, REQ-cli-schema-migration
|
|
331
|
+
export function planInventoryRederivation(workspaceRoot, onlyId) {
|
|
332
|
+
const shards = readShardRelationships(workspaceRoot);
|
|
333
|
+
const facts = new FactClaimIndex(workspaceRoot);
|
|
334
|
+
const plans = [];
|
|
335
|
+
const files = listLaneMarkdownFiles(workspaceRoot, ["requirements"]);
|
|
336
|
+
// The canonical file stem is the id; fall back to every file otherwise.
|
|
337
|
+
const preferred = onlyId === undefined
|
|
338
|
+
? files
|
|
339
|
+
: files.filter((file) => path.basename(file.relativePath, ".md") === onlyId);
|
|
340
|
+
for (const file of preferred.length > 0 ? preferred : files) {
|
|
341
|
+
let result;
|
|
342
|
+
try {
|
|
343
|
+
result = extractFromMarkdown(file.absolutePath);
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
if (onlyId !== undefined && result.entity.id !== onlyId)
|
|
349
|
+
continue;
|
|
350
|
+
const plan = planOne(workspaceRoot, file.relativePath, result.entity, result.relationships, shards, facts);
|
|
351
|
+
if (plan !== null)
|
|
352
|
+
plans.push(plan);
|
|
353
|
+
}
|
|
354
|
+
return plans;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Rewrite the inventory contract keys of one requirement's frontmatter and
|
|
358
|
+
* confirm every other frontmatter field reads back unchanged.
|
|
359
|
+
*/
|
|
360
|
+
function rewriteContract(content, contract) {
|
|
361
|
+
const slice = sliceFrontmatter(content);
|
|
362
|
+
if (slice === null)
|
|
363
|
+
return null;
|
|
364
|
+
const document = parseDocument(slice.text);
|
|
365
|
+
if (document.errors.length > 0)
|
|
366
|
+
return null;
|
|
367
|
+
const current = document.toJS();
|
|
368
|
+
const flowSpan = (span) => {
|
|
369
|
+
const node = document.createNode(span);
|
|
370
|
+
node.flow = true;
|
|
371
|
+
return node;
|
|
372
|
+
};
|
|
373
|
+
for (const [key, value] of Object.entries(contract)) {
|
|
374
|
+
if (isDeepStrictEqual(current[key], value))
|
|
375
|
+
continue;
|
|
376
|
+
const previous = current[key];
|
|
377
|
+
if (key === "semantic_inventory" &&
|
|
378
|
+
Array.isArray(previous) &&
|
|
379
|
+
previous.length === contract.semantic_inventory.length &&
|
|
380
|
+
contract.semantic_inventory.every((entry, index) => isRecord(previous[index]) &&
|
|
381
|
+
previous[index].claim_key === entry.claim_key)) {
|
|
382
|
+
// Same claims in the same order: edit only the fields that changed so
|
|
383
|
+
// untouched entries keep their exact formatting.
|
|
384
|
+
contract.semantic_inventory.forEach((entry, index) => {
|
|
385
|
+
const old = previous[index];
|
|
386
|
+
const fields = new Set([...Object.keys(old), ...Object.keys(entry)]);
|
|
387
|
+
for (const field of fields) {
|
|
388
|
+
const next = entry[field];
|
|
389
|
+
if (isDeepStrictEqual(old[field], next))
|
|
390
|
+
continue;
|
|
391
|
+
if (next === undefined) {
|
|
392
|
+
document.deleteIn([key, index, field]);
|
|
393
|
+
}
|
|
394
|
+
else {
|
|
395
|
+
document.setIn([key, index, field], field === "span" ? flowSpan(entry.span) : next);
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
continue;
|
|
400
|
+
}
|
|
401
|
+
const node = document.createNode(value);
|
|
402
|
+
if (key === "semantic_inventory" && "items" in node) {
|
|
403
|
+
for (const item of node.items) {
|
|
404
|
+
const span = item.get?.("span", true);
|
|
405
|
+
if (span !== undefined)
|
|
406
|
+
span.flow = true;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
document.set(key, node);
|
|
410
|
+
}
|
|
411
|
+
let rendered = document.toString({
|
|
412
|
+
lineWidth: 0,
|
|
413
|
+
flowCollectionPadding: false,
|
|
414
|
+
});
|
|
415
|
+
if (slice.eol === "\r\n")
|
|
416
|
+
rendered = rendered.replace(/\r?\n/g, "\r\n");
|
|
417
|
+
try {
|
|
418
|
+
const before = loadYaml(slice.text);
|
|
419
|
+
const after = loadYaml(rendered);
|
|
420
|
+
if (!isRecord(before) || !isRecord(after))
|
|
421
|
+
return null;
|
|
422
|
+
for (const key of new Set([
|
|
423
|
+
...Object.keys(before),
|
|
424
|
+
...Object.keys(after),
|
|
425
|
+
])) {
|
|
426
|
+
const expected = key in contract
|
|
427
|
+
? contract[key]
|
|
428
|
+
: before[key];
|
|
429
|
+
if (!isDeepStrictEqual(after[key], expected))
|
|
430
|
+
return null;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
catch {
|
|
434
|
+
return null;
|
|
435
|
+
}
|
|
436
|
+
return `${slice.prefix}${rendered}${slice.suffix}`;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Apply the safe re-derivation of one requirement. When `expectedContractHash`
|
|
440
|
+
* is given (the migration plan's evidence), the current re-derivation must
|
|
441
|
+
* still produce exactly that contract. A requirement that no longer drifts is
|
|
442
|
+
* left unchanged, so repeated runs are no-ops.
|
|
443
|
+
*/
|
|
444
|
+
// implements REQ-kibi-proposition-complete-ingestion, REQ-cli-schema-migration
|
|
445
|
+
export function applyInventoryRederivation(workspaceRoot, requirementId, expectedContractHash) {
|
|
446
|
+
const plan = planInventoryRederivation(workspaceRoot, requirementId).find((candidate) => candidate.requirementId === requirementId);
|
|
447
|
+
if (plan === undefined) {
|
|
448
|
+
return { requirementId, path: "", outcome: "unchanged" };
|
|
449
|
+
}
|
|
450
|
+
if (!plan.safe) {
|
|
451
|
+
throw new Error(`Requirement ${requirementId} cannot be re-derived automatically: ${plan.reasons.join("; ")}`);
|
|
452
|
+
}
|
|
453
|
+
if (expectedContractHash !== undefined &&
|
|
454
|
+
plan.contractHash !== expectedContractHash) {
|
|
455
|
+
throw new Error(`Requirement ${requirementId} changed since planning; rerun kibi migrate and approve the new plan.`);
|
|
456
|
+
}
|
|
457
|
+
const absolute = path.join(workspaceRoot, plan.path);
|
|
458
|
+
const content = readText(absolute);
|
|
459
|
+
const next = content === null ? null : rewriteContract(content, plan.contract);
|
|
460
|
+
if (next === null) {
|
|
461
|
+
throw new Error(`Requirement ${requirementId}: the re-derived inventory could not be written without changing other frontmatter fields.`);
|
|
462
|
+
}
|
|
463
|
+
// The written requirement must now pass ingestion exactly as sync sees it.
|
|
464
|
+
const reread = extractFromMarkdownString(next, absolute);
|
|
465
|
+
if (reread.entity.semantic_source_hash !== plan.contract.semantic_source_hash)
|
|
466
|
+
throw new Error(`Requirement ${requirementId}: re-derived inventory did not read back.`);
|
|
467
|
+
writeFileAtomically(absolute, next);
|
|
468
|
+
return {
|
|
469
|
+
requirementId,
|
|
470
|
+
path: plan.path,
|
|
471
|
+
outcome: "rederived",
|
|
472
|
+
summary: plan.summary,
|
|
473
|
+
};
|
|
474
|
+
}
|
|
475
|
+
/** Apply every safe re-derivation; unsafe ones are returned untouched. */
|
|
476
|
+
// implements REQ-kibi-proposition-complete-ingestion, REQ-cli-schema-migration
|
|
477
|
+
export function applySafeInventoryRederivations(workspaceRoot) {
|
|
478
|
+
const plans = planInventoryRederivation(workspaceRoot);
|
|
479
|
+
const rederived = [];
|
|
480
|
+
for (const plan of plans.filter((candidate) => candidate.safe)) {
|
|
481
|
+
rederived.push(applyInventoryRederivation(workspaceRoot, plan.requirementId, plan.contractHash));
|
|
482
|
+
}
|
|
483
|
+
return { rederived, manual: plans.filter((candidate) => !candidate.safe) };
|
|
484
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type EntityLane } from "../../utils/kb-paths.js";
|
|
2
|
+
/** One authored Markdown entity file under a canonical `.kb/<lane>/`. */
|
|
3
|
+
export type LaneMarkdownFile = Readonly<{
|
|
4
|
+
lane: EntityLane;
|
|
5
|
+
absolutePath: string;
|
|
6
|
+
/** Workspace-relative, `/`-separated. */
|
|
7
|
+
relativePath: string;
|
|
8
|
+
}>;
|
|
9
|
+
/** Every authored Markdown entity file in the canonical lanes, sorted. */
|
|
10
|
+
export declare function listLaneMarkdownFiles(workspaceRoot: string, lanes?: readonly EntityLane[]): LaneMarkdownFile[];
|
|
11
|
+
/** A Markdown document split around its YAML frontmatter. */
|
|
12
|
+
export type FrontmatterSlice = Readonly<{
|
|
13
|
+
/** Everything up to and including the opening `---` line. */
|
|
14
|
+
prefix: string;
|
|
15
|
+
/** The frontmatter YAML, ending with a line break. */
|
|
16
|
+
text: string;
|
|
17
|
+
/** The closing `---` line and the body. */
|
|
18
|
+
suffix: string;
|
|
19
|
+
eol: "\n" | "\r\n";
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Split a document the way the Markdown extractor reads it: the frontmatter
|
|
23
|
+
* ends at the next `---` after the opening delimiter. Returns null when that
|
|
24
|
+
* `---` is not at the start of a line, because an edit there could not be
|
|
25
|
+
* read back.
|
|
26
|
+
*/
|
|
27
|
+
export declare function sliceFrontmatter(content: string): FrontmatterSlice | null;
|
|
28
|
+
/**
|
|
29
|
+
* The value of one top-level frontmatter key, read from its own line without
|
|
30
|
+
* parsing the whole document (test files carry large receipt histories).
|
|
31
|
+
* Falls back to a full parse when the value spans several lines. Returns
|
|
32
|
+
* `undefined` when the key is absent or the frontmatter does not parse.
|
|
33
|
+
*/
|
|
34
|
+
export declare function readTopLevelField(frontmatter: string, key: string): unknown;
|
|
35
|
+
/**
|
|
36
|
+
* Set one top-level scalar frontmatter key, leaving every other byte of the
|
|
37
|
+
* document unchanged: the key's line is replaced in place, or appended as the
|
|
38
|
+
* last frontmatter key when absent. Returns null when the key spans several
|
|
39
|
+
* lines or the edit would not read back as exactly that change.
|
|
40
|
+
*/
|
|
41
|
+
export declare function withTopLevelField(content: string, key: string, value: string): string | null;
|
|
42
|
+
/**
|
|
43
|
+
* Remove one top-level scalar frontmatter key, leaving every other byte of
|
|
44
|
+
* the document unchanged: only the key's line and its line break go. Returns
|
|
45
|
+
* the content unchanged when the key is absent. Returns null when the key
|
|
46
|
+
* spans several lines or the edit would not read back as exactly that
|
|
47
|
+
* change (the key gone, every other key parsing identically).
|
|
48
|
+
*/
|
|
49
|
+
export declare function withoutTopLevelField(content: string, key: string): string | null;
|
|
50
|
+
/** Replace a file's bytes atomically. */
|
|
51
|
+
export declare function writeFileAtomically(filePath: string, content: string): void;
|
|
52
|
+
export declare function readText(filePath: string): string | null;
|
|
53
|
+
//# sourceMappingURL=kb-sources.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kb-sources.d.ts","sourceRoot":"","sources":["../../../src/operations/migration/kb-sources.ts"],"names":[],"mappings":"AA8BA,OAAO,EAEL,KAAK,UAAU,EAEhB,MAAM,yBAAyB,CAAC;AAEjC,yEAAyE;AAEzE,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,IAAI,EAAE,UAAU,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,YAAY,EAAE,MAAM,CAAC;CACtB,CAAC,CAAC;AAuBH,0EAA0E;AAE1E,wBAAgB,qBAAqB,CACnC,aAAa,EAAE,MAAM,EACrB,KAAK,GAAE,SAAS,UAAU,EAAiB,GAC1C,gBAAgB,EAAE,CAkBpB;AAED,6DAA6D;AAE7D,MAAM,MAAM,gBAAgB,GAAG,QAAQ,CAAC;IACtC,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,IAAI,GAAG,MAAM,CAAC;CACpB,CAAC,CAAC;AAEH;;;;;GAKG;AAEH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAczE;AAUD;;;;;GAKG;AAEH,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAe3E;AAeD;;;;;GAKG;AAEH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GACZ,MAAM,GAAG,IAAI,CAyBf;AAQD;;;;;;GAMG;AAEH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,GACV,MAAM,GAAG,IAAI,CAsBf;AAED,yCAAyC;AAEzC,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAK3E;AAGD,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMxD"}
|