kibi-cli 2.30.0 → 2.31.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.
Files changed (62) hide show
  1. package/dist/cli-operation-metadata.d.ts +1 -1
  2. package/dist/cli-operation-metadata.js +1 -1
  3. package/dist/cli-register-reporting.d.ts.map +1 -1
  4. package/dist/cli-register-reporting.js +23 -2
  5. package/dist/commands/check-certificates.d.ts +52 -0
  6. package/dist/commands/check-certificates.d.ts.map +1 -0
  7. package/dist/commands/check-certificates.js +163 -0
  8. package/dist/commands/discovery-table.d.ts.map +1 -1
  9. package/dist/commands/discovery-table.js +14 -2
  10. package/dist/commands/report.js +3 -3
  11. package/dist/commands/signoff.d.ts.map +1 -1
  12. package/dist/commands/signoff.js +4 -1
  13. package/dist/operations/planning/apply-plan.js +5 -5
  14. package/dist/operations/proof/baseline-diff.d.ts +1 -1
  15. package/dist/operations/proof/baseline-diff.js +1 -1
  16. package/dist/operations/proof/impact.d.ts +10 -4
  17. package/dist/operations/proof/impact.d.ts.map +1 -1
  18. package/dist/operations/proof/impact.js +27 -7
  19. package/dist/public/diagnostic-usage.js +2 -2
  20. package/dist/public/operations/catalog.d.ts +4 -4
  21. package/dist/public/operations/specs/check-rules.generated.d.ts +1 -1
  22. package/dist/public/operations/specs/check-rules.generated.d.ts.map +1 -1
  23. package/dist/public/operations/specs/check-rules.generated.js +3 -1
  24. package/dist/public/operations/specs/check.d.ts +1 -1
  25. package/dist/public/operations/specs/reporting.d.ts +4 -4
  26. package/dist/public/operations/specs/reporting.js +7 -7
  27. package/dist/public/skills/kibi-commit-review/SKILL.md +4 -3
  28. package/dist/public/skills/kibi-decisions/SKILL.md +1 -1
  29. package/dist/public/skills/kibi-decisions/resources/signoff-views.md +3 -2
  30. package/dist/public/skills/kibi-freshness/SKILL.md +2 -2
  31. package/dist/public/skills/kibi-usage/SKILL.md +2 -2
  32. package/dist/public/skills/kibi-usage/resources/proof.md +36 -4
  33. package/dist/public/skills/kibi-usage/resources/workflows.md +1 -1
  34. package/dist/report/html-report.css +11 -4
  35. package/dist/report/html-report.d.ts +2 -2
  36. package/dist/report/html-report.d.ts.map +1 -1
  37. package/dist/report/html-report.js +27 -21
  38. package/dist/report/report-view.d.ts +2 -2
  39. package/dist/report/report-view.js +2 -2
  40. package/dist/signoff/collect.d.ts.map +1 -1
  41. package/dist/signoff/collect.js +5 -1
  42. package/dist/signoff/html.js +3 -3
  43. package/dist/signoff/model.d.ts +7 -2
  44. package/dist/signoff/model.d.ts.map +1 -1
  45. package/dist/signoff/model.js +6 -2
  46. package/dist/traceability/staged-consistency.d.ts.map +1 -1
  47. package/dist/traceability/staged-consistency.js +3 -1
  48. package/dist/utils/rule-registry.generated.d.ts +10 -0
  49. package/dist/utils/rule-registry.generated.d.ts.map +1 -1
  50. package/dist/utils/rule-registry.generated.js +12 -0
  51. package/package.json +2 -2
  52. package/src/public/diagnostic-usage.ts +3 -3
  53. package/src/public/operations/specs/check-rules.generated.ts +3 -1
  54. package/src/public/operations/specs/reporting.ts +7 -7
  55. package/src/public/skills/kibi-commit-review/SKILL.md +4 -3
  56. package/src/public/skills/kibi-decisions/SKILL.md +1 -1
  57. package/src/public/skills/kibi-decisions/resources/signoff-views.md +3 -2
  58. package/src/public/skills/kibi-freshness/SKILL.md +2 -2
  59. package/src/public/skills/kibi-usage/SKILL.md +2 -2
  60. package/src/public/skills/kibi-usage/resources/proof.md +36 -4
  61. package/src/public/skills/kibi-usage/resources/workflows.md +1 -1
  62. package/templates/github/kibi-badge.yml +1 -1
@@ -62,7 +62,9 @@ export const SELECTABLE_RULE_NAMES = [
62
62
  "supersedes-reason-acknowledged",
63
63
  "policy-ownership",
64
64
  "policy-markers",
65
+ "kb-consistency",
66
+ "kb-consistency-unresolved",
65
67
  ];
66
68
  // implements REQ-006
67
69
  /** Comma-separated "Allowed:" fragment for the kb_check rules description. */
68
- export const SELECTABLE_RULES_ALLOWED = "must-priority-coverage, symbol-coverage, symbol-traceability, symbol-granularity, no-dangling-refs, source-relationship-parity, branch-store-not-compiled, source-path-dangling, no-cycles, required-fields, deprecated-adr-no-successor, superseded-requirement-open, scenario-feasibility, scenario-feasibility-unknown, exception-claim-keys, numeric-string-value, rule-key-arguments-missing, domain-contradictions, logic-coverage, rule-safety, rule-verifiability, query-plan-safety, req-status-vocabulary, strict-fact-shape, strict-req-fact-pairing, predicate-verifiability, strict-readiness, semantic-completeness, related-requirement-unmodeled, proof-contract-symbols, entity-id-style, domain-redundancy, domain-implication, subject-key-identity, subject-key-shape, ontology-quality, exception-unapproved, exception-approval-self-attested, agent-requirement-unapproved, requirement-rationale-missing, symbol-owner-superseded, adr-unlinked, adr-proposed, predicate-schema-conformance, entity-context-missing, entity-context-acknowledged, decision-firm-unreferenced, decision-firm-superseded, decision-firm-edited, supersedes-reason-missing, supersedes-reason-acknowledged, policy-ownership, policy-markers";
70
+ export const SELECTABLE_RULES_ALLOWED = "must-priority-coverage, symbol-coverage, symbol-traceability, symbol-granularity, no-dangling-refs, source-relationship-parity, branch-store-not-compiled, source-path-dangling, no-cycles, required-fields, deprecated-adr-no-successor, superseded-requirement-open, scenario-feasibility, scenario-feasibility-unknown, exception-claim-keys, numeric-string-value, rule-key-arguments-missing, domain-contradictions, logic-coverage, rule-safety, rule-verifiability, query-plan-safety, req-status-vocabulary, strict-fact-shape, strict-req-fact-pairing, predicate-verifiability, strict-readiness, semantic-completeness, related-requirement-unmodeled, proof-contract-symbols, entity-id-style, domain-redundancy, domain-implication, subject-key-identity, subject-key-shape, ontology-quality, exception-unapproved, exception-approval-self-attested, agent-requirement-unapproved, requirement-rationale-missing, symbol-owner-superseded, adr-unlinked, adr-proposed, predicate-schema-conformance, entity-context-missing, entity-context-acknowledged, decision-firm-unreferenced, decision-firm-superseded, decision-firm-edited, supersedes-reason-missing, supersedes-reason-acknowledged, policy-ownership, policy-markers, kb-consistency, kb-consistency-unresolved";
@@ -12,7 +12,7 @@ export declare const checkSpec: {
12
12
  readonly type: "string";
13
13
  readonly enum: readonly string[];
14
14
  };
15
- readonly description: "Optional rule subset. Allowed: must-priority-coverage, symbol-coverage, symbol-traceability, symbol-granularity, no-dangling-refs, source-relationship-parity, branch-store-not-compiled, source-path-dangling, no-cycles, required-fields, deprecated-adr-no-successor, superseded-requirement-open, scenario-feasibility, scenario-feasibility-unknown, exception-claim-keys, numeric-string-value, rule-key-arguments-missing, domain-contradictions, logic-coverage, rule-safety, rule-verifiability, query-plan-safety, req-status-vocabulary, strict-fact-shape, strict-req-fact-pairing, predicate-verifiability, strict-readiness, semantic-completeness, related-requirement-unmodeled, proof-contract-symbols, entity-id-style, domain-redundancy, domain-implication, subject-key-identity, subject-key-shape, ontology-quality, exception-unapproved, exception-approval-self-attested, agent-requirement-unapproved, requirement-rationale-missing, symbol-owner-superseded, adr-unlinked, adr-proposed, predicate-schema-conformance, entity-context-missing, entity-context-acknowledged, decision-firm-unreferenced, decision-firm-superseded, decision-firm-edited, supersedes-reason-missing, supersedes-reason-acknowledged, policy-ownership, policy-markers. If omitted, server runs canonical and advisory rules plus the full-KB qualityDiagnostics audit scan, including usage telemetry acceptance when evidence exists; migration rules run only when explicitly selected. Advisory and migration findings are non-blocking qualityDiagnostics. If supplied, server preserves scoped validation and skips the full-KB advisory scan.";
15
+ readonly description: "Optional rule subset. Allowed: must-priority-coverage, symbol-coverage, symbol-traceability, symbol-granularity, no-dangling-refs, source-relationship-parity, branch-store-not-compiled, source-path-dangling, no-cycles, required-fields, deprecated-adr-no-successor, superseded-requirement-open, scenario-feasibility, scenario-feasibility-unknown, exception-claim-keys, numeric-string-value, rule-key-arguments-missing, domain-contradictions, logic-coverage, rule-safety, rule-verifiability, query-plan-safety, req-status-vocabulary, strict-fact-shape, strict-req-fact-pairing, predicate-verifiability, strict-readiness, semantic-completeness, related-requirement-unmodeled, proof-contract-symbols, entity-id-style, domain-redundancy, domain-implication, subject-key-identity, subject-key-shape, ontology-quality, exception-unapproved, exception-approval-self-attested, agent-requirement-unapproved, requirement-rationale-missing, symbol-owner-superseded, adr-unlinked, adr-proposed, predicate-schema-conformance, entity-context-missing, entity-context-acknowledged, decision-firm-unreferenced, decision-firm-superseded, decision-firm-edited, supersedes-reason-missing, supersedes-reason-acknowledged, policy-ownership, policy-markers, kb-consistency, kb-consistency-unresolved. If omitted, server runs canonical and advisory rules plus the full-KB qualityDiagnostics audit scan, including usage telemetry acceptance when evidence exists; migration rules run only when explicitly selected. Advisory and migration findings are non-blocking qualityDiagnostics. If supplied, server preserves scoped validation and skips the full-KB advisory scan.";
16
16
  };
17
17
  readonly sourceFiles: {
18
18
  readonly type: "array";
@@ -125,7 +125,7 @@ export declare const findGapsSpec: {
125
125
  * + bound-symbol code scope) and hand the Prolog coverage stage a
126
126
  * TestId -> BindingHash dict. This is the default binding mode since slice 3;
127
127
  * KIBI_PROOF_BINDING_MODE=strict-snapshot opts out (receipts then match only
128
- * against the whole-workspace snapshot they were proven on).
128
+ * against the whole-workspace snapshot they were produced on).
129
129
  */
130
130
  export declare function currentProofBindingMode(): "per_contract" | "strict_snapshot";
131
131
  export declare function perContractTestBindings(context: OperationContext): Promise<string | null>;
@@ -141,7 +141,7 @@ export declare function executeCoverage(input: CoverageInput, context: Operation
141
141
  export declare const coverageSpec: {
142
142
  readonly name: "kb_coverage";
143
143
  readonly cliName: "coverage";
144
- readonly description: "Generate curated structural coverage and conservative end-to-end requirement proof reports for requirements, symbols, or grouped types. Use it to ask which requirements are proven and what blocks the rest; use kb_find_gaps for a plain list of missing links and kb_check for rule violations. Reports include the compatible repair plan plus typed kibi.migration-plan.v2 actions; semantic and E2E actions remain review/execution work. Paginated plans identify incomplete scope and no mutation occurs.";
144
+ readonly description: "Generate curated structural coverage and conservative end-to-end requirement proof reports for requirements, symbols, or grouped types. Use it to ask which requirements are tested end to end, how strong each requirement's evidence is (evidenceLevel: proved, tested, asserted or unverified), and what blocks the rest; use kb_find_gaps for a plain list of missing links and kb_check for rule violations. Reports include the compatible repair plan plus typed kibi.migration-plan.v2 actions; semantic and E2E actions remain review/execution work. Paginated plans identify incomplete scope and no mutation occurs.";
145
145
  readonly businessInputSchema: {
146
146
  readonly type: "object";
147
147
  readonly properties: {
@@ -161,13 +161,13 @@ export declare const coverageSpec: {
161
161
  readonly includePassing: {
162
162
  readonly type: "boolean";
163
163
  readonly default: false;
164
- readonly description: "Also return rows that are already proven or not applicable. By default only rows that still need repair are returned.";
164
+ readonly description: "Also return rows that are already tested or not applicable. By default only rows that still need repair are returned.";
165
165
  };
166
166
  readonly statuses: {
167
167
  readonly type: "array";
168
168
  readonly items: {
169
169
  readonly type: "string";
170
- readonly enum: readonly ["proven", "missing", "unresolved", "not_applicable"];
170
+ readonly enum: readonly ["tested", "missing", "unresolved", "not_applicable"];
171
171
  };
172
172
  readonly description: "Requirement proof-status filter (req mode): include only rows whose proofStatus is listed. Selecting statuses implies include-passing; not_applicable rows carry their typed applicability reason in proofStages.applicability.reason. The summary always reflects the whole KB.";
173
173
  };
@@ -30,7 +30,7 @@ function validateEntityType(type) {
30
30
  }
31
31
  }
32
32
  const COVERAGE_PROOF_STATUSES = new Set([
33
- "proven",
33
+ "tested",
34
34
  "missing",
35
35
  "unresolved",
36
36
  "not_applicable",
@@ -120,7 +120,7 @@ export const findGapsSpec = {
120
120
  * + bound-symbol code scope) and hand the Prolog coverage stage a
121
121
  * TestId -> BindingHash dict. This is the default binding mode since slice 3;
122
122
  * KIBI_PROOF_BINDING_MODE=strict-snapshot opts out (receipts then match only
123
- * against the whole-workspace snapshot they were proven on).
123
+ * against the whole-workspace snapshot they were produced on).
124
124
  */
125
125
  // implements REQ-kibi-verification-evidence-contract
126
126
  export function currentProofBindingMode() {
@@ -286,13 +286,13 @@ export async function executeCoverage(input, context) {
286
286
  },
287
287
  };
288
288
  const fullyCovered = Number(enrichedPayload.summary?.fullyCovered ?? 0);
289
- const proofProven = Number(enrichedPayload.summary?.proofProven ?? 0);
289
+ const proofTested = Number(enrichedPayload.summary?.proofTested ?? 0);
290
290
  const total = Number(enrichedPayload.summary?.total ?? 0);
291
291
  return {
292
292
  content: [
293
293
  {
294
294
  type: "text",
295
- text: `Coverage summary: ${fullyCovered} structurally covered and ${proofProven} proven out of ${total}.`,
295
+ text: `Coverage summary: ${fullyCovered} structurally covered and ${proofTested} tested end to end out of ${total}.`,
296
296
  },
297
297
  ],
298
298
  structuredContent: enrichedPayload,
@@ -306,7 +306,7 @@ export async function executeCoverage(input, context) {
306
306
  export const coverageSpec = {
307
307
  name: "kb_coverage",
308
308
  cliName: "coverage",
309
- description: "Generate curated structural coverage and conservative end-to-end requirement proof reports for requirements, symbols, or grouped types. Use it to ask which requirements are proven and what blocks the rest; use kb_find_gaps for a plain list of missing links and kb_check for rule violations. Reports include the compatible repair plan plus typed kibi.migration-plan.v2 actions; semantic and E2E actions remain review/execution work. Paginated plans identify incomplete scope and no mutation occurs.",
309
+ description: "Generate curated structural coverage and conservative end-to-end requirement proof reports for requirements, symbols, or grouped types. Use it to ask which requirements are tested end to end, how strong each requirement's evidence is (evidenceLevel: proved, tested, asserted or unverified), and what blocks the rest; use kb_find_gaps for a plain list of missing links and kb_check for rule violations. Reports include the compatible repair plan plus typed kibi.migration-plan.v2 actions; semantic and E2E actions remain review/execution work. Paginated plans identify incomplete scope and no mutation occurs.",
310
310
  businessInputSchema: {
311
311
  type: "object",
312
312
  properties: {
@@ -324,13 +324,13 @@ export const coverageSpec = {
324
324
  includePassing: {
325
325
  type: "boolean",
326
326
  default: false,
327
- description: "Also return rows that are already proven or not applicable. By default only rows that still need repair are returned.",
327
+ description: "Also return rows that are already tested or not applicable. By default only rows that still need repair are returned.",
328
328
  },
329
329
  statuses: {
330
330
  type: "array",
331
331
  items: {
332
332
  type: "string",
333
- enum: ["proven", "missing", "unresolved", "not_applicable"],
333
+ enum: ["tested", "missing", "unresolved", "not_applicable"],
334
334
  },
335
335
  description: "Requirement proof-status filter (req mode): include only rows whose proofStatus is listed. Selecting statuses implies include-passing; not_applicable rows carry their typed applicability reason in proofStages.applicability.reason. The summary always reflects the whole KB.",
336
336
  },
@@ -2,7 +2,7 @@
2
2
  id: kibi-commit-review
3
3
  name: kibi-commit-review
4
4
  description: "Use when kibi check --staged or the Kibi pre-commit hook blocks a commit (kibi_impact_evidence_missing, symbols_manifest_stale, symbol_granularity_violation, symbol-coverage, kibi check-generated drift, Staged impact review failed), or when preparing a commit or pull-request impact review. Covers reading the per-file Detail lines, authoring .kb/symbols.yaml symbol entries through kb_upsert, kibi sync --refresh-symbol-coordinates, staging the tracked Kibi evidence with git add, kb_prepare_impact_review for a staged or diff scope, the kibi signoff requirements summary to show before a commit, and how merge commits and migration renames are judged."
5
- version: 1.2.0
5
+ version: 1.2.1
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -85,8 +85,9 @@ requirement with its statement (before and after for a rewrite), firmness,
85
85
  origin, scenarios and proof state. Put it in your reply unchanged (in the
86
86
  messaging tool's message when replies go through one), then add one or two
87
87
  sentences on why the requirements changed. Offer the full page with
88
- `kibi signoff --format html --open`, or attach or publish
89
- `.kb/briefs/signoff/latest.html` when your host can carry a file or a page;
88
+ `kibi signoff --format html --open`, or publish `.kb/briefs/signoff/latest.html`
89
+ as a rendered page when your host has a page tool (the Artifact tool in Claude
90
+ apps); never attach the `.html` as a file, which chat apps show as raw source;
90
91
  past 15 requirements the Markdown stops and only the page lists them all.
91
92
  Host details: `kibi-decisions`, `resources/signoff-views.md`. `--no-proof` skips the proof lookup, which reads coverage and is slow
92
93
  on a large knowledge base. The summary is not an approval: never set
@@ -2,7 +2,7 @@
2
2
  id: kibi-decisions
3
3
  name: kibi-decisions
4
4
  description: "Use when the person states a rule or decision (must, never, always, from now on, we decided), when a Kibi hook asks to confirm or warns about an edit to code that implements a firm requirement, when the Stop hook says source files changed but nothing was recorded, when kb_check quotes requirement_statement_unverified, or when a request conflicts with a recorded requirement or ADR. Covers reading firmness and origin, recording a person's rule as firm with origin.ref, superseding with a Why this changed section, the kb_compile_intent unresolved/reviewCandidates/conflictReviews loop, asking before overriding a firm rule, and putting decisions to the person as one numbered kibi signoff --questions view."
5
- version: 1.2.0
5
+ version: 1.2.1
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -13,7 +13,8 @@ statements and lists that render in any chat or messaging surface. Put it in
13
13
  your reply unchanged: never wrap it in a code block, summarize it or retell a
14
14
  requirement in your own words. Every run also writes
15
15
  `.kb/briefs/signoff/latest.json`, `latest.md` and `latest.html` (git-ignored);
16
- `latest.html` is a self-contained page with the full view.
16
+ `latest.html` is a self-contained page with the full view, meant to be opened
17
+ in a browser or published as a page, not attached as a file.
17
18
 
18
19
  ## Showing it on your host
19
20
 
@@ -21,7 +22,7 @@ requirement in your own words. Every run also writes
21
22
  | --- | --- |
22
23
  | Claude Code, Codex, Cursor, ZCode, VS Code chat | Paste the default output; `/kibi-signoff` (Claude Code, Cursor, ZCode) runs it. Offer `kibi signoff --format html --open` for the page |
23
24
  | OpenCode terminal | `kibi signoff --format md` and paste the fenced block unchanged: kibi-opencode draws it as a card, and `/kibi-signoff` reopens it |
24
- | Replies sent through a messaging tool (cloud or project threads, chat bots) | Pass the default output as the message text, and attach or publish `.kb/briefs/signoff/latest.html` next to it when the tool can carry a file or a page |
25
+ | Replies sent through a messaging tool (cloud or project threads, chat bots) | Pass the default output as the message text. Share `latest.html` only as a rendered page: in Claude apps (claude.ai, the mobile and desktop apps, Claude Code on the web) publish it with the Artifact tool and give its link. Never attach the `.html` as a file: the Claude apps, Slack and most chat apps show it as raw source or a download. With no page tool, the message text is the whole view |
25
26
  | VS Code or Cursor with the kibi-vscode extension | The **Kibi: Show Requirements Signoff** panel follows every run |
26
27
  | Remote machine, no browser | Give the person the path of `latest.html` |
27
28
 
@@ -2,7 +2,7 @@
2
2
  id: kibi-freshness
3
3
  name: kibi-freshness
4
4
  description: Check exact Git attachment, branch migration/quarantine, compiled-store freshness, source linkage, and repair state before decisions or writes.
5
- version: 2.0.0
5
+ version: 2.1.0
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -53,7 +53,7 @@ echo '{}' | npx --no-install kibi status --input -
53
53
  `committed_with_repairs`, follow required typed `nextActions`; never retry the
54
54
  original operation.
55
55
 
56
- For every freshness, branch, or completion question, call `kb_status` first, then `kb_query` the entities and source files that status names, then `kb_check` as the last Kibi call before answering. Never skip the query step, even when status alone seems to answer the question. If another query or write follows a check, run `kb_check` again before answering. When asked whether requirements are consistent or proven, run `kb_query`, then `kb_check` with the domain-contradictions rule, then `kb_coverage`, and read whether the analysis was complete. Report any unmodeled or unknown clause as incomplete analysis, not as consistent. Only when every clause is fully modeled and compatible, state plainly that no conflict was found. For authorized knowledge changes, keep the exact supplied target and intended relationship edges, and discover and query those targets first. Validate the payload with `kb_upsert` and `dryRun: true`, then perform the authorized `kb_upsert` with that same payload and read the result back exactly before the final checks. A passing dry run is validation, not completion. Distinct authorized payloads may need several sequential writes, each validated and read back, but never retry a mutation that already committed. If a mutation returns `committed_with_repairs`, follow its typed `nextActions` instead of repeating the original operation.
56
+ For every freshness, branch, or completion question, call `kb_status` first, then `kb_query` the entities and source files that status names, then `kb_check` as the last Kibi call before answering. Never skip the query step, even when status alone seems to answer the question. If another query or write follows a check, run `kb_check` again before answering. When asked whether requirements are consistent or proven, run `kb_query`, then `kb_check` with the rules `domain-contradictions`, `kb-consistency` and `kb-consistency-unresolved`, then `kb_coverage`, and read whether the analysis was complete. `domain-contradictions` compares facts two at a time; `kb-consistency` checks every fact of a property together, so a clean pairwise result is not proof. Report a `kb-consistency` violation as a conflict, name every requirement it lists, and give superseding or changing one of them as the next step; never edit or delete facts to make the check pass. Report a context `kb-consistency-unresolved` names as unresolved, never as consistent, with the step that would make it comparable. Report any unmodeled or unknown clause as incomplete analysis, not as consistent. Only when every clause is fully modeled and compatible, state plainly that no conflict was found. For authorized knowledge changes, keep the exact supplied target and intended relationship edges, and discover and query those targets first. Validate the payload with `kb_upsert` and `dryRun: true`, then perform the authorized `kb_upsert` with that same payload and read the result back exactly before the final checks. A passing dry run is validation, not completion. Distinct authorized payloads may need several sequential writes, each validated and read back, but never retry a mutation that already committed. If a mutation returns `committed_with_repairs`, follow its typed `nextActions` instead of repeating the original operation.
57
57
 
58
58
  ## Guidance
59
59
 
@@ -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.22.0
5
+ version: 2.24.0
6
6
  kibiCompatibility: ">=1.0.0"
7
7
  tags:
8
8
  - kibi
@@ -168,7 +168,7 @@ End every task with these five independent fields:
168
168
  taskOutcome: complete | interim | blocked
169
169
  kbState: clean_fresh | stale | dirty | legacy_compat | not_evaluated
170
170
  verificationState: fresh | dirty | unavailable | not_evaluated
171
- proofState: proven | mixed | unresolved | not_evaluated
171
+ proofState: tested | mixed | unresolved | not_evaluated
172
172
  limitationDisposition: none | accepted | unaccepted | not_applicable
173
173
  ```
174
174
 
@@ -1,6 +1,6 @@
1
1
  # Proof and Verification Workflow
2
2
 
3
- Use this resource when a requirement must be proven before handoff, when
3
+ Use this resource when a requirement must be tested end to end before handoff, when
4
4
  wiring a proof-bearing test, or when `kb_ingest_proof` or `kibi prove`
5
5
  rejected evidence.
6
6
 
@@ -97,9 +97,9 @@ Cosmetic edits (descriptions, labels) never stale proof. Execution-relevant
97
97
  edits (command, artifact, targets, options, bindings, contract) change the
98
98
  effective fingerprint and do.
99
99
 
100
- ## What counts toward proofProven
100
+ ## What counts toward proofTested
101
101
 
102
- A requirement is proven only by its scenarios' tests, and a scenario test
102
+ A requirement reaches `proofStatus: tested` only through its scenarios' tests, and a scenario test
103
103
  counts only when it is an **end-to-end** test with a valid, fresh, passing
104
104
  receipt for the current snapshot.
105
105
 
@@ -109,7 +109,7 @@ receipt for the current snapshot.
109
109
  `source` path contains `e2e`) counts as end-to-end; anything else is
110
110
  `unknown` scope.
111
111
  - A `unit` or `integration` receipt is still recorded on the test entity, but
112
- it does not move `proofProven` for a behavioural requirement: the
112
+ it does not move `proofTested` for a behavioural requirement: the
113
113
  requirement keeps the `missing_passing_e2e` gap in `proofGaps`. The one
114
114
  exception is a scenario whose specifying requirements are all grounded only
115
115
  in component-scope UI predicates (`ui_pattern`, `same_pattern`,
@@ -120,6 +120,38 @@ receipt for the current snapshot.
120
120
  receipt does not change it, and a `passing` status without a fresh receipt
121
121
  proves nothing.
122
122
 
123
+ ## Evidence levels
124
+
125
+ Every requirement row also carries `evidenceLevel`, the strength of what backs
126
+ it, and `evidence`, the entries that earned it (each with `kind`, `scope` and
127
+ `level`):
128
+
129
+ - `proved`: a re-checkable certificate covers every case. No proof kind issues
130
+ certificates yet, so nothing reaches it today.
131
+ - `tested`: `proofStatus` is `tested`; fresh E2E receipts cover every linked
132
+ scenario.
133
+ - `asserted`: a person stands behind the statement (approved, or firm by
134
+ `firmness` or a non-agent origin) but nothing current checks it.
135
+ - `unverified`: an agent wrote it, no person approved it, nothing checks it.
136
+
137
+ Report the level as it is. Never call an `asserted` or `unverified`
138
+ requirement proven or tested, and never call `tested` proved. Firmness is a
139
+ separate axis: it says how sure the person is, not how strong the evidence is.
140
+
141
+ ## Knowledge-base certificates
142
+
143
+ `kb_check` (`kibi check`) proves facts about the KB itself in its
144
+ `kb-consistency` rule and re-checks each answer with an independent checker:
145
+ property facts are consistent (a model per subject, property and scope, or an
146
+ irreducible contradiction core), predicate facts and allow/deny decisions are
147
+ consistent, and stored rules are stratified. It catches facts that contradict
148
+ only together, which the pairwise `domain-contradictions` rule misses. A
149
+ `kb-consistency` violation names the core facts and the requirements behind
150
+ them: supersede or change one of those requirements; never edit the facts so
151
+ the check passes. Quote a `kb-consistency-unresolved` diagnostic as
152
+ unresolved, never as consistent. Opposing rule pairs and scenario
153
+ feasibility are not certified yet; their own rules still decide them.
154
+
123
155
  ## Attempt semantics (factual, never optimistic)
124
156
 
125
157
  - `attempts: {status: "complete", entries: [...]}` — known history; the
@@ -9,7 +9,7 @@ success flag):
9
9
  taskOutcome: complete | interim | blocked
10
10
  kbState: clean_fresh | stale | dirty | legacy_compat | not_evaluated
11
11
  verificationState: fresh | dirty | unavailable | not_evaluated
12
- proofState: proven | mixed | unresolved | not_evaluated
12
+ proofState: tested | mixed | unresolved | not_evaluated
13
13
  limitationDisposition: none | accepted | unaccepted | not_applicable
14
14
  ```
15
15
 
@@ -341,7 +341,7 @@ h1 span {
341
341
  content: "";
342
342
  background: var(--amber);
343
343
  }
344
- .requirement--proven::before {
344
+ .requirement--tested::before {
345
345
  background: var(--green);
346
346
  }
347
347
  .requirement--unresolved::before {
@@ -356,6 +356,13 @@ h1 span {
356
356
  align-items: start;
357
357
  justify-content: space-between;
358
358
  }
359
+ .evidence-level {
360
+ margin-left: 6px;
361
+ opacity: 0.75;
362
+ font-weight: 700;
363
+ text-transform: uppercase;
364
+ letter-spacing: .06em;
365
+ }
359
366
  .requirement__id {
360
367
  margin-bottom: 7px;
361
368
  color: var(--muted);
@@ -380,7 +387,7 @@ h1 span {
380
387
  letter-spacing: .07em;
381
388
  text-transform: uppercase;
382
389
  }
383
- .proof-badge--proven {
390
+ .proof-badge--tested {
384
391
  border-color: rgba(98, 230, 167, 0.25);
385
392
  color: var(--green);
386
393
  background: rgba(98, 230, 167, 0.08);
@@ -1001,7 +1008,7 @@ h1 {
1001
1008
  .requirement::before {
1002
1009
  background: var(--warning);
1003
1010
  }
1004
- .requirement--proven::before {
1011
+ .requirement--tested::before {
1005
1012
  background: var(--success);
1006
1013
  }
1007
1014
  .requirement--unresolved::before {
@@ -1024,7 +1031,7 @@ h1 {
1024
1031
  background: rgba(242, 184, 75, 0.07);
1025
1032
  font: 800 9px / 1.2 var(--mono);
1026
1033
  }
1027
- .proof-badge--proven {
1034
+ .proof-badge--tested {
1028
1035
  border-color: rgba(99, 201, 154, 0.3);
1029
1036
  color: var(--success);
1030
1037
  background: rgba(99, 201, 154, 0.07);
@@ -15,7 +15,7 @@ export type HtmlReportInput = Readonly<{
15
15
  generatedAt: Date;
16
16
  repository?: ReportRepository;
17
17
  }>;
18
- export declare function firstFailingProofGate(gates: readonly ProofGateKey[], passes: (gate: ProofGateKey) => boolean): ProofGateKey | "proven";
19
- export declare function earliestUnmetGate(row: UnknownRecord): ProofGateKey | "proven";
18
+ export declare function firstFailingProofGate(gates: readonly ProofGateKey[], passes: (gate: ProofGateKey) => boolean): ProofGateKey | "tested";
19
+ export declare function earliestUnmetGate(row: UnknownRecord): ProofGateKey | "tested";
20
20
  export declare function renderHtmlReport(input: HtmlReportInput): string;
21
21
  //# sourceMappingURL=html-report.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"html-report.d.ts","sourceRoot":"","sources":["../../src/report/html-report.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,gBAAgB,EAMtB,MAAM,iBAAiB,CAAC;AAGzB,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAuB9D,eAAO,MAAM,UAAU,6FACqE,CAAC;AAG7F,eAAO,MAAM,wBAAwB,gEAC0B,CAAC;AAEhE,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,SAAS,aAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB,CAAC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,YAAY,EAAE,kBAAkB,CAAC;IACjC,OAAO,EAAE,kBAAkB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,IAAI,CAAC;IAClB,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B,CAAC,CAAC;AAkNH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,GACtC,YAAY,GAAG,QAAQ,CAKzB;AAID,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,GAAG,QAAQ,CAM7E;AA8YD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAuM/D"}
1
+ {"version":3,"file":"html-report.d.ts","sourceRoot":"","sources":["../../src/report/html-report.ts"],"names":[],"mappings":"AAUA,OAAO,EACL,KAAK,YAAY,EAGlB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,gBAAgB,EAMtB,MAAM,iBAAiB,CAAC;AAGzB,MAAM,MAAM,aAAa,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAuB9D,eAAO,MAAM,UAAU,6FACqE,CAAC;AAG7F,eAAO,MAAM,wBAAwB,gEAC0B,CAAC;AAEhE,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,OAAO,EAAE,aAAa,CAAC;IACvB,IAAI,EAAE,SAAS,aAAa,EAAE,CAAC;IAC/B,IAAI,CAAC,EAAE,aAAa,CAAC;CACtB,CAAC,CAAC;AAEH,MAAM,MAAM,eAAe,GAAG,QAAQ,CAAC;IACrC,YAAY,EAAE,kBAAkB,CAAC;IACjC,OAAO,EAAE,kBAAkB,CAAC;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,IAAI,CAAC;IAClB,UAAU,CAAC,EAAE,gBAAgB,CAAC;CAC/B,CAAC,CAAC;AAkNH,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,SAAS,YAAY,EAAE,EAC9B,MAAM,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,OAAO,GACtC,YAAY,GAAG,QAAQ,CAKzB;AAID,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,aAAa,GAAG,YAAY,GAAG,QAAQ,CAM7E;AAqZD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAuM/D"}
@@ -143,7 +143,7 @@ function implementationOwned(stages) {
143
143
  return productionSymbols.every((symbol) => !missingCoordinates.has(symbol));
144
144
  }
145
145
  function passesProofGate(row, gate) {
146
- if (row.proofStatus === "proven")
146
+ if (row.proofStatus === "tested")
147
147
  return true;
148
148
  const stages = record(row.proofStages);
149
149
  if (gate === "semantic") {
@@ -158,7 +158,7 @@ function passesProofGate(row, gate) {
158
158
  if (gate === "e2e") {
159
159
  return stagePassed(stages, "scenarioTests") && hasEndToEndTest(stages);
160
160
  }
161
- return row.proofStatus === "proven";
161
+ return row.proofStatus === "tested";
162
162
  }
163
163
  function proofGates(rows) {
164
164
  const definitions = [
@@ -197,13 +197,13 @@ export function firstFailingProofGate(gates, passes) {
197
197
  if (!passes(gate))
198
198
  return gate;
199
199
  }
200
- return "proven";
200
+ return "tested";
201
201
  }
202
202
  // implements REQ-kibi-html-health-report
203
203
  // covered_by TEST-kibi-html-health-report
204
204
  export function earliestUnmetGate(row) {
205
- if (row.proofStatus === "proven")
206
- return "proven";
205
+ if (row.proofStatus === "tested")
206
+ return "tested";
207
207
  return firstFailingProofGate(["semantic", "scenario", "implementation", "e2e", "evidence"], (gate) => passesProofGate(row, gate));
208
208
  }
209
209
  function evidenceStage(passingE2e, testSources, repository) {
@@ -401,15 +401,15 @@ function rowSeverity(row) {
401
401
  return 0;
402
402
  if (gaps.includes("stale_proof_receipt"))
403
403
  return 1;
404
- if (row.proofStatus !== "proven")
404
+ if (row.proofStatus !== "tested")
405
405
  return 2;
406
406
  return 3;
407
407
  }
408
408
  function rowStates(row) {
409
409
  const states = new Set();
410
410
  const gaps = strings(row.proofGaps);
411
- if (row.proofStatus === "proven")
412
- states.add("proven");
411
+ if (row.proofStatus === "tested")
412
+ states.add("tested");
413
413
  else
414
414
  states.add("attention");
415
415
  if (gaps.includes("stale_proof_receipt"))
@@ -430,8 +430,8 @@ function renderRequirement(row, repository) {
430
430
  const proofStatus = text(row.proofStatus, "missing");
431
431
  const proofGaps = strings(row.proofGaps);
432
432
  const proofAdvisories = strings(row.proofAdvisories);
433
- const blockingGaps = proofStatus === "proven" ? [] : proofGaps;
434
- const advisories = proofStatus === "proven"
433
+ const blockingGaps = proofStatus === "tested" ? [] : proofGaps;
434
+ const advisories = proofStatus === "tested"
435
435
  ? [
436
436
  ...proofAdvisories,
437
437
  ...proofGaps.filter((gap) => !proofAdvisories.includes(gap)),
@@ -439,7 +439,8 @@ function renderRequirement(row, repository) {
439
439
  : proofAdvisories;
440
440
  const conflicts = records(record(record(row.proofStages).contradictions).conflicts).filter((conflict) => text(conflict.status) === "contradiction");
441
441
  const stages = requirementStages(row, repository);
442
- const badgeLabel = proofStatus === "proven" ? "Proven" : "Needs attention";
442
+ const badgeLabel = proofStatus === "tested" ? "Tested" : "Needs attention";
443
+ const evidenceLevel = text(row.evidenceLevel, "unverified");
443
444
  const requirementSource = sourceCoordinate({
444
445
  path: text(record(record(row.proofStages).sourceCoordinates).requirementPath, text(row.source)),
445
446
  }) ?? sourceCoordinate({ path: text(row.source) });
@@ -447,7 +448,7 @@ function renderRequirement(row, repository) {
447
448
  return `<article class="requirement requirement--${escapeHtml(proofStatus)}" data-state="${rowStates(row)}" data-gate="${escapeHtml(gate)}">
448
449
  <header class="requirement__header">
449
450
  <div>
450
- <div class="requirement__id">${linkedLabel(id, sourceWebUrl(repository, requirementSource))}</div>
451
+ <div class="requirement__id">${linkedLabel(id, sourceWebUrl(repository, requirementSource))} <span class="evidence-level evidence-level--${escapeHtml(evidenceLevel)}" title="Evidence level">${escapeHtml(evidenceLevel)}</span></div>
451
452
  <h3>${linkedLabel(title, sourceWebUrl(repository, requirementSource))}</h3>
452
453
  </div>
453
454
  <span class="proof-badge proof-badge--${escapeHtml(proofStatus)}">${escapeHtml(badgeLabel)}</span>
@@ -458,6 +459,11 @@ function renderRequirement(row, repository) {
458
459
  ${renderIssueList(advisories, "proof-advisories", "advisory", "advisories")}
459
460
  </article>`;
460
461
  }
462
+ // implements REQ-kibi-evidence-levels
463
+ function evidenceCount(rows, level) {
464
+ return rows.filter((row) => text(row.evidenceLevel, "unverified") === level)
465
+ .length;
466
+ }
461
467
  function metric(label, value, tone = "") {
462
468
  return `<div class="metric${tone ? ` metric--${tone}` : ""}"><span>${escapeHtml(label)}</span><strong>${value.toLocaleString("en-US")}</strong></div>`;
463
469
  }
@@ -513,7 +519,7 @@ function reportIdentity(input) {
513
519
  function renderFilters(counts) {
514
520
  const labels = {
515
521
  all: "All",
516
- proven: "Proven",
522
+ tested: "Tested",
517
523
  attention: "Needs attention",
518
524
  stale: "Stale evidence",
519
525
  contradiction: "Contradictions",
@@ -537,10 +543,10 @@ export function renderHtmlReport(input) {
537
543
  const total = count(summary.total);
538
544
  const notApplicable = count(summary.proofNotApplicable);
539
545
  const currentRequirements = Math.max(0, total - notApplicable);
540
- const proven = count(summary.proofProven);
546
+ const tested = count(summary.proofTested);
541
547
  const proofPercent = currentRequirements === 0
542
548
  ? 0
543
- : Math.round((proven / currentRequirements) * 100);
549
+ : Math.round((tested / currentRequirements) * 100);
544
550
  const missingScenarios = currentRows.filter((row) => strings(row.proofGaps).includes("missing_scenario")).length;
545
551
  const staleEvidence = currentRows.filter((row) => strings(row.proofGaps).includes("stale_proof_receipt")).length;
546
552
  const withoutImplementation = currentRows.filter((row) => strings(row.proofGaps).includes("missing_production_symbol")).length;
@@ -561,12 +567,10 @@ export function renderHtmlReport(input) {
561
567
  })));
562
568
  const identity = reportIdentity({ ...input, repository });
563
569
  const faviconHref = renderKibiFaviconDataUri();
564
- const scoreLabel = currentRequirements === 0
565
- ? "No current requirements"
566
- : "Strict proof coverage";
570
+ const scoreLabel = currentRequirements === 0 ? "No current requirements" : "Tested end to end";
567
571
  const scoreRatio = currentRequirements === 0
568
572
  ? "No current requirements to prove"
569
- : `${proven.toLocaleString("en-US")} of ${currentRequirements.toLocaleString("en-US")} current requirements fully proven end-to-end`;
573
+ : `${tested.toLocaleString("en-US")} of ${currentRequirements.toLocaleString("en-US")} current requirements fully tested end-to-end`;
570
574
  return `<!doctype html>
571
575
  <html lang="en">
572
576
  <head>
@@ -596,7 +600,7 @@ export function renderHtmlReport(input) {
596
600
  <h1>Intent to proof,<br>without the gaps.</h1>
597
601
  <p>Kibi compiles product intent into an inspectable chain of semantics, scenarios, implementation ownership, end-to-end tests, and fresh evidence.</p>
598
602
  </div>
599
- <div class="score" aria-label="${proofPercent}% strict proof coverage, ${proven} of ${currentRequirements} current requirements fully proven end-to-end">
603
+ <div class="score" aria-label="${proofPercent}% tested end to end, ${tested} of ${currentRequirements} current requirements fully tested end-to-end">
600
604
  <div class="score__value">${proofPercent}<span>%</span></div>
601
605
  <div class="score__label">${escapeHtml(scoreLabel)}</div>
602
606
  <div class="score__ratio">${escapeHtml(scoreRatio)}</div>
@@ -613,7 +617,9 @@ export function renderHtmlReport(input) {
613
617
  </section>
614
618
  <section class="metrics" aria-label="Requirement health summary">
615
619
  ${metric("Requirements", currentRequirements)}
616
- ${metric("Strict proof coverage", proven, "good")}
620
+ ${metric("Tested end to end", tested, "good")}
621
+ ${metric("Asserted, no current test", evidenceCount(currentRows, "asserted"), evidenceCount(currentRows, "asserted") ? "warn" : "")}
622
+ ${metric("Unverified", evidenceCount(currentRows, "unverified"), evidenceCount(currentRows, "unverified") ? "warn" : "")}
617
623
  ${metric("Missing scenarios", missingScenarios, missingScenarios ? "warn" : "")}
618
624
  ${metric("Stale E2E evidence", staleEvidence, staleEvidence ? "warn" : "")}
619
625
  ${metric("Contradictions", contradictions.length, contradictions.length ? "bad" : "")}
@@ -1,11 +1,11 @@
1
- export declare const REPORT_FILTERS: readonly ["all", "proven", "attention", "stale", "contradiction"];
1
+ export declare const REPORT_FILTERS: readonly ["all", "tested", "attention", "stale", "contradiction"];
2
2
  export type ReportFilter = (typeof REPORT_FILTERS)[number];
3
3
  export declare const PROOF_GATE_KEYS: readonly ["semantic", "scenario", "implementation", "e2e", "evidence"];
4
4
  export type ProofGateKey = (typeof PROOF_GATE_KEYS)[number];
5
5
  export type RequirementView = Readonly<{
6
6
  text: string;
7
7
  states: readonly string[];
8
- earliestGate: ProofGateKey | "proven";
8
+ earliestGate: ProofGateKey | "tested";
9
9
  }>;
10
10
  export type ReportViewQuery = Readonly<{
11
11
  query: string;
@@ -1,6 +1,6 @@
1
1
  export const REPORT_FILTERS = [
2
2
  "all",
3
- "proven",
3
+ "tested",
4
4
  "attention",
5
5
  "stale",
6
6
  "contradiction",
@@ -24,7 +24,7 @@ export function matchesReportView(row, view) {
24
24
  export function reportFilterCounts(rows) {
25
25
  return {
26
26
  all: rows.length,
27
- proven: rows.filter((row) => row.states.includes("proven")).length,
27
+ tested: rows.filter((row) => row.states.includes("tested")).length,
28
28
  attention: rows.filter((row) => row.states.includes("attention")).length,
29
29
  stale: rows.filter((row) => row.states.includes("stale")).length,
30
30
  contradiction: rows.filter((row) => row.states.includes("contradiction"))
@@ -1 +1 @@
1
- {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../../src/signoff/collect.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAIL,KAAK,YAAY,EAEjB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EAGrB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AASpB,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEhD,2DAA2D;AAC3D,MAAM,MAAM,oBAAoB,GAAG,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;AAE1E,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,qEAAqE;IACrE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;IAC1C,0EAA0E;IAC1E,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACtE,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IAC7D,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC,CAAC;AAuCH,sEAAsE;AACtE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAEpE;AAyGD;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,YAAY,EACnB,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,cAAc,CAAC,CA6JzB;AAGD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,oBAAoB,CAAC,CA8B/B;AAGD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,SAAS,oBAAoB,EAAE,EACvC,GAAG,GAAE,MAAM,IAAuB,GACjC,gBAAgB,CA4BlB;AA+BD;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,MAAM,GACV,oBAAoB,EAAE,CAkDxB"}
1
+ {"version":3,"file":"collect.d.ts","sourceRoot":"","sources":["../../src/signoff/collect.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,KAAK,eAAe,EAErB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAIL,KAAK,YAAY,EAEjB,KAAK,oBAAoB,EACzB,KAAK,gBAAgB,EAGrB,KAAK,cAAc,EACpB,MAAM,YAAY,CAAC;AASpB,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEhD,2DAA2D;AAC3D,MAAM,MAAM,oBAAoB,GAAG,WAAW,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;AAE1E,MAAM,MAAM,kBAAkB,GAAG,QAAQ,CAAC;IACxC,qEAAqE;IACrE,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,MAAM,CAAC;IAC1C,0EAA0E;IAC1E,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACtE,mDAAmD;IACnD,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC;IAC7D,GAAG,CAAC,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC,CAAC;AAuCH,sEAAsE;AACtE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAEpE;AAyGD;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,YAAY,EACnB,IAAI,GAAE,kBAAuB,GAC5B,OAAO,CAAC,cAAc,CAAC,CAiKzB;AAGD;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,YAAY,GAClB,OAAO,CAAC,oBAAoB,CAAC,CA8B/B;AAGD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,SAAS,oBAAoB,EAAE,EACvC,GAAG,GAAE,MAAM,IAAuB,GACjC,gBAAgB,CA4BlB;AA+BD;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,GAAG,EAAE,MAAM,GACV,oBAAoB,EAAE,CAkDxB"}
@@ -151,6 +151,10 @@ export async function collectSignoffSummary(workspaceRoot, scope, deps = {}) {
151
151
  : undefined;
152
152
  const firmness = firmnessOf(entity);
153
153
  const origin = entity.origin;
154
+ // origin.approved_by records who approved an agent-written requirement,
155
+ // the field its evidence level and agent-requirement-unapproved read. The
156
+ // top-level approved_by approves an exception and is not read here.
157
+ const approvedBy = origin?.approved_by;
154
158
  return {
155
159
  id: entity.id,
156
160
  title: flat(entity.title ?? entity.id),
@@ -163,7 +167,7 @@ export async function collectSignoffSummary(workspaceRoot, scope, deps = {}) {
163
167
  ...(firmness ? { firmness } : {}),
164
168
  ...(origin?.kind ? { originKind: origin.kind } : {}),
165
169
  ...(origin?.ref ? { originRef: flat(origin.ref) } : {}),
166
- ...(origin?.approved_by ? { approvedBy: origin.approved_by } : {}),
170
+ ...(approvedBy ? { approvedBy } : {}),
167
171
  supersedes: outgoing(entity.id, "supersedes")
168
172
  .map((id) => readRequirement(id))
169
173
  .filter((ref) => ref !== undefined)
@@ -30,7 +30,7 @@ h2{font-size:16px;margin:28px 0 10px;color:var(--accent)}
30
30
  .badge{font-size:12px;padding:1px 8px;border-radius:999px;border:1px solid var(--rail);color:var(--muted)}
31
31
  .badge--firm{border-color:var(--warn);color:var(--warn)}
32
32
  .badge--exploratory{border-color:var(--signal);color:var(--signal)}
33
- .badge--proven{border-color:var(--ok);color:var(--ok)}
33
+ .badge--tested{border-color:var(--ok);color:var(--ok)}
34
34
  .badge--answered{border-color:var(--ok);color:var(--ok)}
35
35
  .badge--approval{border-color:var(--signal);color:var(--signal);font-weight:600}
36
36
  .callout{margin:12px 0 4px;padding:10px 14px;border:1px solid var(--signal);border-radius:8px;color:var(--text)}
@@ -98,8 +98,8 @@ function requirementCard(requirement, number) {
98
98
  : requirement.scenarios
99
99
  .map((scenario) => `<span class="id">${escapeHtml(scenario.id)}</span>${scenario.title === scenario.id ? "" : ` ${escapeHtml(scenario.title)}`}`)
100
100
  .join("<br>")));
101
- const proven = requirement.proof?.gate === "proven";
102
- details.push(row("Proof", `<span class="badge${proven ? " badge--proven" : ""}">${escapeHtml(proofLabel(requirement.proof))}</span>`));
101
+ const tested = requirement.proof?.gate === "tested";
102
+ details.push(row("Proof", `<span class="badge${tested ? " badge--tested" : ""}">${escapeHtml(proofLabel(requirement.proof))}</span>`));
103
103
  for (const conflict of requirement.proof?.contradictions ?? []) {
104
104
  details.push(row("Contradiction", `<span class="conflict">${escapeHtml(conflict)}</span>`));
105
105
  }
@@ -30,11 +30,16 @@ export type SignoffStatementRef = Readonly<{
30
30
  firmness?: SignoffFirmness;
31
31
  }>;
32
32
  export type SignoffProof = Readonly<{
33
- /** Coverage proof status: proven, missing, unresolved or not_applicable. */
33
+ /** Coverage proof status: tested, missing, unresolved or not_applicable. */
34
34
  status: string;
35
- /** The earliest unmet proof gate, or "proven". */
35
+ /** The earliest unmet proof gate, or "tested". */
36
36
  gate: string;
37
37
  testCount: number;
38
+ /**
39
+ * How strong the evidence is: proved, tested, asserted (a person stands
40
+ * behind it, nothing current checks it) or unverified.
41
+ */
42
+ evidenceLevel?: string;
38
43
  contradictions: readonly string[];
39
44
  }>;
40
45
  export type SignoffRequirement = Readonly<{