agent-nuvira 3.5.7 → 3.5.10

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 (134) hide show
  1. package/README.md +19 -1
  2. package/dist/agents/agents/package-agent.d.ts +22 -0
  3. package/dist/agents/agents/package-agent.d.ts.map +1 -1
  4. package/dist/agents/agents/package-agent.js +92 -4
  5. package/dist/agents/agents/package-agent.js.map +1 -1
  6. package/dist/agents/release-preflight.d.ts +42 -5
  7. package/dist/agents/release-preflight.d.ts.map +1 -1
  8. package/dist/agents/release-preflight.js +82 -5
  9. package/dist/agents/release-preflight.js.map +1 -1
  10. package/dist/cli/chat.d.ts.map +1 -1
  11. package/dist/cli/chat.js +99 -9
  12. package/dist/cli/chat.js.map +1 -1
  13. package/dist/cli/cli-program.d.ts.map +1 -1
  14. package/dist/cli/cli-program.js +6 -0
  15. package/dist/cli/cli-program.js.map +1 -1
  16. package/dist/cli/code-map.d.ts +51 -0
  17. package/dist/cli/code-map.d.ts.map +1 -1
  18. package/dist/cli/code-map.js +174 -2
  19. package/dist/cli/code-map.js.map +1 -1
  20. package/dist/cli/credentials.d.ts.map +1 -1
  21. package/dist/cli/credentials.js +4 -1
  22. package/dist/cli/credentials.js.map +1 -1
  23. package/dist/cli/execute.js +5 -5
  24. package/dist/cli/execute.js.map +1 -1
  25. package/dist/cli/loop-executor.d.ts.map +1 -1
  26. package/dist/cli/loop-executor.js +76 -13
  27. package/dist/cli/loop-executor.js.map +1 -1
  28. package/dist/cli/motion.d.ts +53 -0
  29. package/dist/cli/motion.d.ts.map +1 -0
  30. package/dist/cli/motion.js +516 -0
  31. package/dist/cli/motion.js.map +1 -0
  32. package/dist/config/process-env.d.ts.map +1 -1
  33. package/dist/config/process-env.js +2 -2
  34. package/dist/config/process-env.js.map +1 -1
  35. package/dist/editing/types.d.ts +23 -1
  36. package/dist/editing/types.d.ts.map +1 -1
  37. package/dist/editing/types.js +51 -7
  38. package/dist/editing/types.js.map +1 -1
  39. package/dist/inference/route-resolver.d.ts +39 -0
  40. package/dist/inference/route-resolver.d.ts.map +1 -1
  41. package/dist/inference/route-resolver.js +51 -2
  42. package/dist/inference/route-resolver.js.map +1 -1
  43. package/dist/inference/thinking-replay.d.ts +86 -0
  44. package/dist/inference/thinking-replay.d.ts.map +1 -0
  45. package/dist/inference/thinking-replay.js +110 -0
  46. package/dist/inference/thinking-replay.js.map +1 -0
  47. package/dist/inference/tools.d.ts +9 -0
  48. package/dist/inference/tools.d.ts.map +1 -1
  49. package/dist/inference/tools.js +12 -1
  50. package/dist/inference/tools.js.map +1 -1
  51. package/dist/learning/assessment-protocol.d.ts +120 -0
  52. package/dist/learning/assessment-protocol.d.ts.map +1 -0
  53. package/dist/learning/assessment-protocol.js +236 -0
  54. package/dist/learning/assessment-protocol.js.map +1 -0
  55. package/dist/learning/assessment-turn-context.d.ts +54 -0
  56. package/dist/learning/assessment-turn-context.d.ts.map +1 -0
  57. package/dist/learning/assessment-turn-context.js +71 -0
  58. package/dist/learning/assessment-turn-context.js.map +1 -0
  59. package/dist/learning/exhaustion-report.d.ts +24 -1
  60. package/dist/learning/exhaustion-report.d.ts.map +1 -1
  61. package/dist/learning/exhaustion-report.js +18 -6
  62. package/dist/learning/exhaustion-report.js.map +1 -1
  63. package/dist/learning/machine-facts.d.ts +7 -0
  64. package/dist/learning/machine-facts.d.ts.map +1 -1
  65. package/dist/learning/machine-facts.js +37 -2
  66. package/dist/learning/machine-facts.js.map +1 -1
  67. package/dist/learning/perf-probe.d.ts +140 -0
  68. package/dist/learning/perf-probe.d.ts.map +1 -0
  69. package/dist/learning/perf-probe.js +316 -0
  70. package/dist/learning/perf-probe.js.map +1 -0
  71. package/dist/learning/self-check-discovery.d.ts +117 -0
  72. package/dist/learning/self-check-discovery.d.ts.map +1 -0
  73. package/dist/learning/self-check-discovery.js +334 -0
  74. package/dist/learning/self-check-discovery.js.map +1 -0
  75. package/dist/skills/bundled-skills-phase3.d.ts.map +1 -1
  76. package/dist/skills/bundled-skills-phase3.js +3 -3
  77. package/dist/skills/bundled-skills-phase3.js.map +1 -1
  78. package/dist/skills/sandbox-executor.d.ts.map +1 -1
  79. package/dist/skills/sandbox-executor.js +115 -34
  80. package/dist/skills/sandbox-executor.js.map +1 -1
  81. package/dist/tools/child-agent-runtime.js +19 -1
  82. package/dist/tools/child-agent-runtime.js.map +1 -1
  83. package/dist/tools/credentials-tool.d.ts.map +1 -1
  84. package/dist/tools/credentials-tool.js +4 -1
  85. package/dist/tools/credentials-tool.js.map +1 -1
  86. package/dist/tools/loop-project-context.d.ts +7 -0
  87. package/dist/tools/loop-project-context.d.ts.map +1 -1
  88. package/dist/tools/loop-project-context.js +44 -0
  89. package/dist/tools/loop-project-context.js.map +1 -1
  90. package/dist/tools/modality/motion-tool.d.ts +28 -1
  91. package/dist/tools/modality/motion-tool.d.ts.map +1 -1
  92. package/dist/tools/modality/motion-tool.js +261 -10
  93. package/dist/tools/modality/motion-tool.js.map +1 -1
  94. package/dist/tools/modality/motion.d.ts +403 -3
  95. package/dist/tools/modality/motion.d.ts.map +1 -1
  96. package/dist/tools/modality/motion.js +1096 -41
  97. package/dist/tools/modality/motion.js.map +1 -1
  98. package/dist/tools/pipeline-tool.d.ts.map +1 -1
  99. package/dist/tools/pipeline-tool.js +19 -1
  100. package/dist/tools/pipeline-tool.js.map +1 -1
  101. package/dist/tools/plan-store.d.ts +90 -6
  102. package/dist/tools/plan-store.d.ts.map +1 -1
  103. package/dist/tools/plan-store.js +140 -13
  104. package/dist/tools/plan-store.js.map +1 -1
  105. package/dist/tools/publish-tool.d.ts.map +1 -1
  106. package/dist/tools/publish-tool.js +9 -0
  107. package/dist/tools/publish-tool.js.map +1 -1
  108. package/dist/tools/registry.d.ts.map +1 -1
  109. package/dist/tools/registry.js +59 -7
  110. package/dist/tools/registry.js.map +1 -1
  111. package/dist/tools/tool-loop.d.ts +17 -0
  112. package/dist/tools/tool-loop.d.ts.map +1 -1
  113. package/dist/tools/tool-loop.js +4 -1
  114. package/dist/tools/tool-loop.js.map +1 -1
  115. package/dist/web-dashboard/chat-console.d.ts.map +1 -1
  116. package/dist/web-dashboard/chat-console.js +11 -1
  117. package/dist/web-dashboard/chat-console.js.map +1 -1
  118. package/dist/web-dashboard/motion-data.d.ts +62 -0
  119. package/dist/web-dashboard/motion-data.d.ts.map +1 -0
  120. package/dist/web-dashboard/motion-data.js +91 -0
  121. package/dist/web-dashboard/motion-data.js.map +1 -0
  122. package/dist/web-dashboard/project-context.js +6 -0
  123. package/dist/web-dashboard/project-context.js.map +1 -1
  124. package/dist/web-dashboard/server.d.ts.map +1 -1
  125. package/dist/web-dashboard/server.js +83 -33
  126. package/dist/web-dashboard/server.js.map +1 -1
  127. package/dist/web-dashboard/src/types.d.ts +31 -0
  128. package/dist/web-dashboard/src/types.d.ts.map +1 -1
  129. package/package.json +1 -1
  130. package/src/web-dashboard/public/assets/{index-CzRU84ET.css → index-CXdBvA0N.css} +1 -1
  131. package/src/web-dashboard/public/assets/{index-V0rIqVbg.js → index-DfjkO16t.js} +81 -81
  132. package/src/web-dashboard/public/assets/index-DfjkO16t.js.map +1 -0
  133. package/src/web-dashboard/public/index.html +2 -2
  134. package/src/web-dashboard/public/assets/index-V0rIqVbg.js.map +0 -1
@@ -0,0 +1,120 @@
1
+ /**
2
+ * PROJECT-ASSESSMENT PROTOCOL — the evidence rules for "assess this codebase"
3
+ * asks (audit / code review / "find the bugs").
4
+ *
5
+ * WHY THIS EXISTS (the side-by-side audit, 2026-10-16). Two agents on the SAME
6
+ * model (DeepSeek V4.1 Flash), the same prompt, the same small project
7
+ * (`/Users/dheeraj/Documents/cal`, 12 files, ~276 LOC), told not to change
8
+ * anything. One ran the project's own modules and the real page in a browser;
9
+ * the other — this CLI — reasoned over what it had read, re-created the engine
10
+ * by hand inside `code_execution`, and published the copy's output as the app's
11
+ * behaviour. The comparison isolates four defects that are NOT about model
12
+ * quality, because the model was identical:
13
+ *
14
+ * 1. A COPY WAS REPORTED AS THE ARTIFACT. Its top-severity finding said
15
+ * "typing `alert(1)` into the display and pressing `=` runs the code",
16
+ * "verified" against a hand-copied engine — while the shipped display
17
+ * input is `disabled`, the keyboard filter drops every letter, and no
18
+ * button emits one, so that input cannot be produced at all. The sink is
19
+ * real and LATENT; the reachability claim was false. Worse, its remediation
20
+ * ("reject identifiers in the whitelist") does not close the sink, because
21
+ * a char-code `Function(...)` escape needs only letters, digits, commas and
22
+ * parens — measured against the real module.
23
+ * 2. NO MEASUREMENT. "`999999999!` hangs the tab indefinitely" — measured on
24
+ * the real engine it is ~31 s (3.09 s at n=1e8, linear), and the indefinite
25
+ * case needs more digits than that. A magnitude nobody measured is a
26
+ * guess wearing a severity label.
27
+ * 3. GREEN TESTS READ AS COVERAGE. The project's 10 tests all pass, and all 10
28
+ * drive `evaluateExpression` — while the UI buttons call
29
+ * `evaluateScientific`, which is missing cases for 8 of the 14 buttons. The
30
+ * tested path is not the shipped path; that gap IS the root cause, and the
31
+ * audit that stopped at "tests pass" could not see it.
32
+ * 4. THE ANSWER STOPPED MID-SENTENCE. Its report forward-referenced a
33
+ * "dead code — noted at the end" section, ran out of output budget two
34
+ * findings later, and ended inside a word. A dangling forward reference in a
35
+ * truncated answer costs the reader the whole tail of the report.
36
+ *
37
+ * WHAT THIS MODULE IS. A deterministic, LLM-free classifier plus one block of
38
+ * text. It changes what the agent must be able to SHOW for a finding, not the
39
+ * shape of the report: the strengths that run already had — severity labels,
40
+ * exact `file:line`, mechanism, a fix recipe, the artifact-inheritance check
41
+ * (does the built bundle carry the same bug?), and finishing in seconds — are
42
+ * kept and are named in the block as the format to keep.
43
+ *
44
+ * ROUND TWO (the head-to-head audit, 2026-10-16). A second side-by-side run —
45
+ * same model, same prompt, same snapshot, this time on a Python desktop app
46
+ * (`/Users/dheeraj/Documents/anuj_voice`, 60 modules) — scored this CLI's audit
47
+ * against another agent's. It found six defects the five rules above did not
48
+ * cover, and every one is a SHAPE OF CHECK rather than a missing fact:
49
+ *
50
+ * 6. IT READ THE MODULES AND NOT THE SEAMS. The three findings it missed all
51
+ * lived in the joins: a constant compared against the wrong version
52
+ * (`_MIN_APP_VERSION = '0.1.0'` gating every real add-on out), a manifest
53
+ * field parsed and consumed nowhere (`dependencies`), and a recursive
54
+ * merge that silently drops nested defaults when the file is partial.
55
+ * 7. IT DID NOT RUN THE PROJECT'S OWN TOOLING. The tree shipped
56
+ * `tools/dead_code_audit.py` and a packaging validator, its plan NAMED the
57
+ * tools directory, and it ran neither — while a shipped checker was the
58
+ * artifact that reported the release defect. See `self-check-discovery.ts`.
59
+ * 8. IT CITED A FILE IN THE REPO AS EVIDENCE. It repeated a claim from a
60
+ * prior `ASSESSMENT.md` sitting in the tree without resolving that file's
61
+ * own `file:line` references — which were, on measurement, pointing at the
62
+ * accelerator table rather than the code the claim described.
63
+ * 9. IT ASSERTED A MEASUREMENT IT HAD NOT TAKEN. Its plan reported
64
+ * `14 failed / 422 passed` before any command in the transcript had run,
65
+ * and its appendix documented a command that does not reproduce those
66
+ * numbers. Both are provenance failures, not the model being wrong.
67
+ * 10. IT ASKED A USER WHO WAS NOT THERE for permission to run a read-only
68
+ * probe, and self-answered only because the run was unattended.
69
+ * 11. IT LEFT ITS SCRATCH FILES IN THE TREE IT WAS AUDITING.
70
+ *
71
+ * Rules 6-11 are the mechanical half of that gap: four of them are checks the
72
+ * agent can perform on its own output before delivering it.
73
+ *
74
+ * NARROWNESS IS THE DESIGN. The block is injected ONLY for an assessment ask: a
75
+ * change request ("fix the bug", "add tests") must be byte-identical to a build
76
+ * without this feature, which is why {@link isProjectAssessmentGoal} requires an
77
+ * explicit finding/audit shape rather than the word "review" on its own. An
78
+ * authored ask is excluded via the existing deliverable taxonomy, so "write a
79
+ * review of this novel" never gets a bug-hunting protocol.
80
+ */
81
+ /**
82
+ * The block's rules, written as one message. Kept deterministic (an array of
83
+ * lines joined here) so tests assert on the rules rather than on prose
84
+ * formatting, and so a truncated edit cannot silently drop a rule.
85
+ */
86
+ export declare const ASSESSMENT_PROTOCOL_RULES: readonly string[];
87
+ /**
88
+ * The injected block. Returns '' for every non-assessment ask (the caller then
89
+ * injects nothing, so the turn is byte-identical to one from a build without
90
+ * this module).
91
+ *
92
+ * It deliberately does NOT prescribe a report template: the findings format from
93
+ * a normal run — severity, `file:line`, mechanism, fix — is named as the thing to
94
+ * KEEP, so the protocol adds evidence discipline without flattening the answer.
95
+ */
96
+ export declare function assessmentProtocolBlock(goal: string, opts?: {
97
+ selfChecks?: string;
98
+ }): string;
99
+ /**
100
+ * Is this goal a PROJECT ASSESSMENT — a request for findings about existing code,
101
+ * rather than a change to it or an authored document?
102
+ *
103
+ * Two shapes qualify, and nothing else does:
104
+ * - an explicit finding request ("identify the bugs in the project", "what's
105
+ * broken here") — the shape the side-by-side audit took;
106
+ * - an assessment verb aimed at code ("assess the project at …", "review the
107
+ * codebase", "audit this API").
108
+ *
109
+ * The exclusions are as load-bearing as the matches: requiring a code target keeps
110
+ * "review this sentence" and "review my notes" out, and a LONG-FORM authored ask is
111
+ * excluded so "write a 20 page review of this codebase" stays a document task.
112
+ *
113
+ * The authored exclusion is deliberately the NARROW one (`isLongFormAuthoredGoal`,
114
+ * not `isAuthoredGoal`): the broad predicate is claimed by the word "report", and
115
+ * the verbatim audit goal ends "…report the file and line … this is an assessment
116
+ * only" — a broad guard silently drops exactly the ask this module exists for. The
117
+ * code-target requirement already keeps prose asks that never mention code out.
118
+ */
119
+ export declare function isProjectAssessmentGoal(goal: string): boolean;
120
+ //# sourceMappingURL=assessment-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assessment-protocol.d.ts","sourceRoot":"","sources":["../../src/learning/assessment-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AAyBH;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,EAAE,SAAS,MAAM,EAsEtD,CAAC;AAEF;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,CAAA;CAAO,GACjC,MAAM,CAqBR;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAO7D"}
@@ -0,0 +1,236 @@
1
+ /**
2
+ * PROJECT-ASSESSMENT PROTOCOL — the evidence rules for "assess this codebase"
3
+ * asks (audit / code review / "find the bugs").
4
+ *
5
+ * WHY THIS EXISTS (the side-by-side audit, 2026-10-16). Two agents on the SAME
6
+ * model (DeepSeek V4.1 Flash), the same prompt, the same small project
7
+ * (`/Users/dheeraj/Documents/cal`, 12 files, ~276 LOC), told not to change
8
+ * anything. One ran the project's own modules and the real page in a browser;
9
+ * the other — this CLI — reasoned over what it had read, re-created the engine
10
+ * by hand inside `code_execution`, and published the copy's output as the app's
11
+ * behaviour. The comparison isolates four defects that are NOT about model
12
+ * quality, because the model was identical:
13
+ *
14
+ * 1. A COPY WAS REPORTED AS THE ARTIFACT. Its top-severity finding said
15
+ * "typing `alert(1)` into the display and pressing `=` runs the code",
16
+ * "verified" against a hand-copied engine — while the shipped display
17
+ * input is `disabled`, the keyboard filter drops every letter, and no
18
+ * button emits one, so that input cannot be produced at all. The sink is
19
+ * real and LATENT; the reachability claim was false. Worse, its remediation
20
+ * ("reject identifiers in the whitelist") does not close the sink, because
21
+ * a char-code `Function(...)` escape needs only letters, digits, commas and
22
+ * parens — measured against the real module.
23
+ * 2. NO MEASUREMENT. "`999999999!` hangs the tab indefinitely" — measured on
24
+ * the real engine it is ~31 s (3.09 s at n=1e8, linear), and the indefinite
25
+ * case needs more digits than that. A magnitude nobody measured is a
26
+ * guess wearing a severity label.
27
+ * 3. GREEN TESTS READ AS COVERAGE. The project's 10 tests all pass, and all 10
28
+ * drive `evaluateExpression` — while the UI buttons call
29
+ * `evaluateScientific`, which is missing cases for 8 of the 14 buttons. The
30
+ * tested path is not the shipped path; that gap IS the root cause, and the
31
+ * audit that stopped at "tests pass" could not see it.
32
+ * 4. THE ANSWER STOPPED MID-SENTENCE. Its report forward-referenced a
33
+ * "dead code — noted at the end" section, ran out of output budget two
34
+ * findings later, and ended inside a word. A dangling forward reference in a
35
+ * truncated answer costs the reader the whole tail of the report.
36
+ *
37
+ * WHAT THIS MODULE IS. A deterministic, LLM-free classifier plus one block of
38
+ * text. It changes what the agent must be able to SHOW for a finding, not the
39
+ * shape of the report: the strengths that run already had — severity labels,
40
+ * exact `file:line`, mechanism, a fix recipe, the artifact-inheritance check
41
+ * (does the built bundle carry the same bug?), and finishing in seconds — are
42
+ * kept and are named in the block as the format to keep.
43
+ *
44
+ * ROUND TWO (the head-to-head audit, 2026-10-16). A second side-by-side run —
45
+ * same model, same prompt, same snapshot, this time on a Python desktop app
46
+ * (`/Users/dheeraj/Documents/anuj_voice`, 60 modules) — scored this CLI's audit
47
+ * against another agent's. It found six defects the five rules above did not
48
+ * cover, and every one is a SHAPE OF CHECK rather than a missing fact:
49
+ *
50
+ * 6. IT READ THE MODULES AND NOT THE SEAMS. The three findings it missed all
51
+ * lived in the joins: a constant compared against the wrong version
52
+ * (`_MIN_APP_VERSION = '0.1.0'` gating every real add-on out), a manifest
53
+ * field parsed and consumed nowhere (`dependencies`), and a recursive
54
+ * merge that silently drops nested defaults when the file is partial.
55
+ * 7. IT DID NOT RUN THE PROJECT'S OWN TOOLING. The tree shipped
56
+ * `tools/dead_code_audit.py` and a packaging validator, its plan NAMED the
57
+ * tools directory, and it ran neither — while a shipped checker was the
58
+ * artifact that reported the release defect. See `self-check-discovery.ts`.
59
+ * 8. IT CITED A FILE IN THE REPO AS EVIDENCE. It repeated a claim from a
60
+ * prior `ASSESSMENT.md` sitting in the tree without resolving that file's
61
+ * own `file:line` references — which were, on measurement, pointing at the
62
+ * accelerator table rather than the code the claim described.
63
+ * 9. IT ASSERTED A MEASUREMENT IT HAD NOT TAKEN. Its plan reported
64
+ * `14 failed / 422 passed` before any command in the transcript had run,
65
+ * and its appendix documented a command that does not reproduce those
66
+ * numbers. Both are provenance failures, not the model being wrong.
67
+ * 10. IT ASKED A USER WHO WAS NOT THERE for permission to run a read-only
68
+ * probe, and self-answered only because the run was unattended.
69
+ * 11. IT LEFT ITS SCRATCH FILES IN THE TREE IT WAS AUDITING.
70
+ *
71
+ * Rules 6-11 are the mechanical half of that gap: four of them are checks the
72
+ * agent can perform on its own output before delivering it.
73
+ *
74
+ * NARROWNESS IS THE DESIGN. The block is injected ONLY for an assessment ask: a
75
+ * change request ("fix the bug", "add tests") must be byte-identical to a build
76
+ * without this feature, which is why {@link isProjectAssessmentGoal} requires an
77
+ * explicit finding/audit shape rather than the word "review" on its own. An
78
+ * authored ask is excluded via the existing deliverable taxonomy, so "write a
79
+ * review of this novel" never gets a bug-hunting protocol.
80
+ */
81
+ import { isLongFormAuthoredGoal } from './deliverable-class.js';
82
+ /**
83
+ * Verbs that ask for judgement ABOUT the code rather than a change TO it.
84
+ * `analyse`/`analyze` are here because "analyse the codebase" is the same ask.
85
+ */
86
+ const ASSESS_VERBS = /\b(assess|audit|review|critique|inspect|analyse|analyze|evaluate)\b/i;
87
+ /**
88
+ * The thing being judged. Required alongside a bare verb so "review this
89
+ * sentence" cannot pull a code-audit protocol into the turn.
90
+ */
91
+ const CODE_TARGETS = /\b(code\s*-?\s*base|project|repo(?:sitory)?|source\s+tree|files?|modules?|packages?|app(?:lication)?|backend|frontend|api|scripts?|src)\b/i;
92
+ /** "find the bugs", "identify issues", "list defects", "spot the risks" … */
93
+ const FIND_FLAWS = /\b(find|finding|identify|list|spot|locate|uncover|report|surface|hunt\s+for|look\s+for)\b[^.!?]{0,60}\b(bugs?|issues?|defects?|problems?|flaws?|vulnerabilit(?:y|ies)|smells?|errors?|risks?|weaknesses?|bugs?\s+and)\b/i;
94
+ /** "what's wrong with this project", "what is broken in the code" … */
95
+ const WHATS_WRONG = /\bwhat(?:'s| is| are| s)\s+(?:wrong|broken|missing|bad|the\s+(?:bugs?|issues?|problems?|risks?|defects?))\b/i;
96
+ /**
97
+ * The block's rules, written as one message. Kept deterministic (an array of
98
+ * lines joined here) so tests assert on the rules rather than on prose
99
+ * formatting, and so a truncated edit cannot silently drop a rule.
100
+ */
101
+ export const ASSESSMENT_PROTOCOL_RULES = [
102
+ '1. MEASURE THE ARTIFACT, NOT A COPY.',
103
+ ' Run the project\'s own code: import the real module, call the real function,',
104
+ ' drive the real page, endpoint or CLI. Never paste a copy of the logic into a',
105
+ ' scratch script and present its output as the app\'s behaviour — a copy can',
106
+ ' differ from the shipped code, and that gap is where wrong findings come from.',
107
+ ' If you did reason from a copy, tag the finding `REASONED` instead of `MEASURED`.',
108
+ ' MEASURE THE CONSEQUENCE TOO: when the impact is data loss or corruption, run',
109
+ ' the path against a temp copy and report the observed end state, not a guess.',
110
+ '',
111
+ '2. REACHABILITY BEFORE SEVERITY.',
112
+ ' Before a UI / endpoint / input defect is called real, show that a user can',
113
+ ' produce the triggering input: name the handler, the filter, the disabled',
114
+ ' field, the route. A sink with no reachable input is LATENT — say "latent" and',
115
+ ' name the path that would make it live. Never describe an unreachable path as',
116
+ ' something the user can type.',
117
+ '',
118
+ '3. QUANTIFY RESOURCE CLAIMS.',
119
+ ' Every hang / freeze / leak / DoS / slow-path claim needs a number you',
120
+ ' measured (use the real code and say what you ran: "3.09 s at n=1e8, linear"),',
121
+ ' and anything you did not measure must be labelled an extrapolation.',
122
+ ' If you cannot measure it, tag the finding `UNMEASURED` and say which command',
123
+ ' would produce the number — an admitted gap is honest, a magnitude you never',
124
+ ' measured reads as a fact and is not one.',
125
+ '',
126
+ '4. GREEN TESTS ARE NOT COVERAGE.',
127
+ ' Say what the tests actually call and whether that is the path users take.',
128
+ ' When a tested function and the shipped dispatch differ, name which one is',
129
+ ' tested and which one runs — that gap is usually the root cause of the bug',
130
+ ' you just found, and it survives every green test run.',
131
+ '',
132
+ '5. FINISH WHAT YOU REFERENCE.',
133
+ ' Never forward-reference a section you might not deliver ("noted at the end",',
134
+ ' "see below"): write it where you reference it. If you are near your output',
135
+ ' limit, cut SCOPE, not the end of a sentence — close the finding you are in,',
136
+ ' then add a final `## Not covered` list. An answer that stops mid-sentence is',
137
+ ' a failed answer, however good the part before it was.',
138
+ '',
139
+ '6. CHECK THE SEAMS, NOT ONLY THE MODULES. For every CONSTANT, ask what it is',
140
+ ' compared against (a version gate against a hardcoded floor disables the',
141
+ ' feature it guards); for every PARSED FIELD, find its consumer (an unread',
142
+ ' config or manifest key is a capability that does not exist); for every',
143
+ ' recursive MERGE or default table, feed it PARTIAL input and see which',
144
+ ' defaults survive.',
145
+ '',
146
+ '7. RUN WHAT THE PROJECT ALREADY SHIPS. Run the self-checks below and any you',
147
+ ' find (a `tools/` auditor, a validator, a CI script) before concluding — a',
148
+ ' shipped checker is the highest-provenance evidence there is, and cannot be',
149
+ ' a hallucination. Give a delegate the EXACT file or suite to run, and read',
150
+ ' its "not found" as nothing tested. Skipping one? Name it as a gap, never',
151
+ ' silently.',
152
+ '',
153
+ '8. A FILE IN THE REPO IS A CLAIM, NOT A FACT. A prior report, notes file or',
154
+ ' README is evidence of what someone asserted, not of what the code does.',
155
+ ' Resolve its `file:line` references yourself first, saying which you checked.',
156
+ '',
157
+ '9. NEVER CLAIM A MEASUREMENT YOU HAVE NOT TAKEN. A number belongs in the',
158
+ ' answer only after the command that produced it ran IN THIS TURN; never mark',
159
+ ' a step done on a result you have not seen, and re-run every command you cite',
160
+ ' to confirm it prints the numbers beside it. An unreproducible command',
161
+ ' invalidates its finding.',
162
+ '',
163
+ '10. DECIDE; DO NOT ASK FOR WHAT YOU MAY ALREADY DO. Reading, listing, searching',
164
+ ' and running read-only probes are yours. Ask only where the answer is the',
165
+ ' user\'s call and cannot be inferred; with nobody there, record the choice',
166
+ ' you made, never a question.',
167
+ '',
168
+ '11. LEAVE THE TREE AS YOU FOUND IT. Keep scratch files, probes and reports',
169
+ ' OUTSIDE the audited repository (a temp dir) and say where; if a deliverable',
170
+ ' must land in the tree, name every file you added and what to delete.',
171
+ ];
172
+ /**
173
+ * The injected block. Returns '' for every non-assessment ask (the caller then
174
+ * injects nothing, so the turn is byte-identical to one from a build without
175
+ * this module).
176
+ *
177
+ * It deliberately does NOT prescribe a report template: the findings format from
178
+ * a normal run — severity, `file:line`, mechanism, fix — is named as the thing to
179
+ * KEEP, so the protocol adds evidence discipline without flattening the answer.
180
+ */
181
+ export function assessmentProtocolBlock(goal, opts = {}) {
182
+ if (!isProjectAssessmentGoal(goal))
183
+ return '';
184
+ const parts = [
185
+ '## ⚠️ TASK PROTOCOL: PROJECT ASSESSMENT (findings, not changes)',
186
+ 'Keep the report shape you already use — severity-labelled findings, exact',
187
+ '`file:line`, the mechanism, a fix, and which artifacts inherit the bug. Add',
188
+ 'these evidence rules on top; a finding that breaks one is not yet a finding:',
189
+ '',
190
+ ...ASSESSMENT_PROTOCOL_RULES,
191
+ '',
192
+ 'Also: read the whole tree in as FEW passes as possible (one call listing many',
193
+ 'paths beats one call per file) BEFORE you start verifying, and record the exact',
194
+ 'command and observed output next to each finding so it can be re-run by someone',
195
+ 'who was not there.',
196
+ ];
197
+ // The project's own checks (see `self-check-discovery.ts`) are appended only
198
+ // when the caller found some, so a project that declares none produces the
199
+ // exact block a build without that module produces.
200
+ const selfChecks = (opts.selfChecks || '').trim();
201
+ if (selfChecks)
202
+ parts.push('', selfChecks);
203
+ return parts.join('\n');
204
+ }
205
+ /**
206
+ * Is this goal a PROJECT ASSESSMENT — a request for findings about existing code,
207
+ * rather than a change to it or an authored document?
208
+ *
209
+ * Two shapes qualify, and nothing else does:
210
+ * - an explicit finding request ("identify the bugs in the project", "what's
211
+ * broken here") — the shape the side-by-side audit took;
212
+ * - an assessment verb aimed at code ("assess the project at …", "review the
213
+ * codebase", "audit this API").
214
+ *
215
+ * The exclusions are as load-bearing as the matches: requiring a code target keeps
216
+ * "review this sentence" and "review my notes" out, and a LONG-FORM authored ask is
217
+ * excluded so "write a 20 page review of this codebase" stays a document task.
218
+ *
219
+ * The authored exclusion is deliberately the NARROW one (`isLongFormAuthoredGoal`,
220
+ * not `isAuthoredGoal`): the broad predicate is claimed by the word "report", and
221
+ * the verbatim audit goal ends "…report the file and line … this is an assessment
222
+ * only" — a broad guard silently drops exactly the ask this module exists for. The
223
+ * code-target requirement already keeps prose asks that never mention code out.
224
+ */
225
+ export function isProjectAssessmentGoal(goal) {
226
+ const g = (goal || '').trim();
227
+ if (!g)
228
+ return false;
229
+ // A long-form authored deliverable wins: the prose IS the deliverable here.
230
+ if (isLongFormAuthoredGoal(g))
231
+ return false;
232
+ if (FIND_FLAWS.test(g) || WHATS_WRONG.test(g))
233
+ return true;
234
+ return ASSESS_VERBS.test(g) && CODE_TARGETS.test(g);
235
+ }
236
+ //# sourceMappingURL=assessment-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assessment-protocol.js","sourceRoot":"","sources":["../../src/learning/assessment-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+EG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AAEhE;;;GAGG;AACH,MAAM,YAAY,GAAG,sEAAsE,CAAC;AAE5F;;;GAGG;AACH,MAAM,YAAY,GAChB,4IAA4I,CAAC;AAE/I,6EAA6E;AAC7E,MAAM,UAAU,GACd,0NAA0N,CAAC;AAE7N,uEAAuE;AACvE,MAAM,WAAW,GACf,8GAA8G,CAAC;AAEjH;;;;GAIG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAsB;IAC1D,sCAAsC;IACtC,iFAAiF;IACjF,iFAAiF;IACjF,+EAA+E;IAC/E,kFAAkF;IAClF,qFAAqF;IACrF,iFAAiF;IACjF,iFAAiF;IACjF,EAAE;IACF,kCAAkC;IAClC,+EAA+E;IAC/E,6EAA6E;IAC7E,kFAAkF;IAClF,iFAAiF;IACjF,iCAAiC;IACjC,EAAE;IACF,8BAA8B;IAC9B,0EAA0E;IAC1E,kFAAkF;IAClF,wEAAwE;IACxE,iFAAiF;IACjF,gFAAgF;IAChF,6CAA6C;IAC7C,EAAE;IACF,kCAAkC;IAClC,8EAA8E;IAC9E,8EAA8E;IAC9E,8EAA8E;IAC9E,0DAA0D;IAC1D,EAAE;IACF,+BAA+B;IAC/B,iFAAiF;IACjF,+EAA+E;IAC/E,gFAAgF;IAChF,iFAAiF;IACjF,0DAA0D;IAC1D,EAAE;IACF,8EAA8E;IAC9E,4EAA4E;IAC5E,6EAA6E;IAC7E,2EAA2E;IAC3E,0EAA0E;IAC1E,sBAAsB;IACtB,EAAE;IACF,8EAA8E;IAC9E,8EAA8E;IAC9E,+EAA+E;IAC/E,8EAA8E;IAC9E,6EAA6E;IAC7E,cAAc;IACd,EAAE;IACF,6EAA6E;IAC7E,4EAA4E;IAC5E,iFAAiF;IACjF,EAAE;IACF,0EAA0E;IAC1E,gFAAgF;IAChF,iFAAiF;IACjF,0EAA0E;IAC1E,6BAA6B;IAC7B,EAAE;IACF,iFAAiF;IACjF,8EAA8E;IAC9E,+EAA+E;IAC/E,iCAAiC;IACjC,EAAE;IACF,4EAA4E;IAC5E,iFAAiF;IACjF,0EAA0E;CAC3E,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,UAAU,uBAAuB,CACrC,IAAY,EACZ,OAAgC,EAAE;IAElC,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG;QACZ,iEAAiE;QACjE,2EAA2E;QAC3E,6EAA6E;QAC7E,8EAA8E;QAC9E,EAAE;QACF,GAAG,yBAAyB;QAC5B,EAAE;QACF,+EAA+E;QAC/E,iFAAiF;QACjF,iFAAiF;QACjF,oBAAoB;KACrB,CAAC;IACF,6EAA6E;IAC7E,2EAA2E;IAC3E,oDAAoD;IACpD,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAClD,IAAI,UAAU;QAAE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;IAC3C,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IACrB,4EAA4E;IAC5E,IAAI,sBAAsB,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC3D,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * ASSESSMENT TURN CONTEXT — the ONE seam every surface builds an assessment ask
3
+ * through.
4
+ *
5
+ * WHY THIS EXISTS. `assessment-protocol.ts` answers "what must a findings turn be
6
+ * able to show?", `self-check-discovery.ts` answers "what does this project
7
+ * already check?", and `perf-probe.ts` answers "how would its startup cost be
8
+ * measured?" — three modules, one prompt section, and four turn entries that all
9
+ * run assessment asks (the CLI chat and the dashboard and the gateway chat through
10
+ * `ChatCommand.runChatAnswer`, `nuvira execute` through `runLoopExecutor` and
11
+ * `runPipelineTool`, and a delegated sub-agent through the child runtime).
12
+ *
13
+ * Measured before this module existed: the section was assembled inline in
14
+ * `chat.ts`, so it reached exactly one entry. An assessment run through
15
+ * `nuvira execute` — the surface a batch/scripted audit actually uses — got the
16
+ * plain ask with none of the rules, which is the "capability lands on one surface
17
+ * and quietly misses three" drift `src/parity/surfaces.ts` was written to make
18
+ * visible. Assembling it here means the surfaces cannot disagree about what an
19
+ * assessment ask is, and a rule added once lands everywhere.
20
+ *
21
+ * THE ORDER IS THE DESIGN, not an optimisation detail. `isProjectAssessmentGoal`
22
+ * is a pure regex over the goal and runs FIRST: for every ordinary turn — the
23
+ * overwhelming majority — this function does no filesystem work at all and returns
24
+ * an empty block, so such a turn is byte-identical to one from a build without any
25
+ * of these modules. Only once a turn IS an assessment ask does it read the project
26
+ * directory.
27
+ *
28
+ * BEST-EFFORT BY CONTRACT, like the modules it composes. A missing/unreadable
29
+ * workspace, or a project with nothing discoverable, yields the rules block alone:
30
+ * the protocol still applies, and no turn is ever broken by a discovery failure.
31
+ */
32
+ import type { MachineFacts } from './machine-facts.js';
33
+ /** What an assessment turn contributes to the prompt, and how much of it. */
34
+ export interface AssessmentTurnContext {
35
+ /** True when the goal is a findings ask — the detector, exposed once. */
36
+ isAssessment: boolean;
37
+ /** The prompt section: '' for every non-assessment ask. */
38
+ block: string;
39
+ /** How many of the project's own checks were named (0 when none/not probed). */
40
+ selfChecks: number;
41
+ /** Whether a performance-probe section was included. */
42
+ perfProbes: boolean;
43
+ }
44
+ /**
45
+ * Build the assessment section for one turn.
46
+ *
47
+ * @param goal the user's ask, verbatim (the detector reads it, so do not rewrite it first)
48
+ * @param dir the directory the turn is scoped to (the project being assessed)
49
+ * @param opts.facts machine facts, injectable for tests
50
+ */
51
+ export declare function buildAssessmentTurnContext(goal: string, dir: string, opts?: {
52
+ facts?: MachineFacts;
53
+ }): AssessmentTurnContext;
54
+ //# sourceMappingURL=assessment-turn-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assessment-turn-context.d.ts","sourceRoot":"","sources":["../../src/learning/assessment-turn-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAKH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD,6EAA6E;AAC7E,MAAM,WAAW,qBAAqB;IACpC,yEAAyE;IACzE,YAAY,EAAE,OAAO,CAAC;IACtB,2DAA2D;IAC3D,KAAK,EAAE,MAAM,CAAC;IACd,gFAAgF;IAChF,UAAU,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,UAAU,EAAE,OAAO,CAAC;CACrB;AAKD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,YAAY,CAAA;CAAO,GAClC,qBAAqB,CAyBvB"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * ASSESSMENT TURN CONTEXT — the ONE seam every surface builds an assessment ask
3
+ * through.
4
+ *
5
+ * WHY THIS EXISTS. `assessment-protocol.ts` answers "what must a findings turn be
6
+ * able to show?", `self-check-discovery.ts` answers "what does this project
7
+ * already check?", and `perf-probe.ts` answers "how would its startup cost be
8
+ * measured?" — three modules, one prompt section, and four turn entries that all
9
+ * run assessment asks (the CLI chat and the dashboard and the gateway chat through
10
+ * `ChatCommand.runChatAnswer`, `nuvira execute` through `runLoopExecutor` and
11
+ * `runPipelineTool`, and a delegated sub-agent through the child runtime).
12
+ *
13
+ * Measured before this module existed: the section was assembled inline in
14
+ * `chat.ts`, so it reached exactly one entry. An assessment run through
15
+ * `nuvira execute` — the surface a batch/scripted audit actually uses — got the
16
+ * plain ask with none of the rules, which is the "capability lands on one surface
17
+ * and quietly misses three" drift `src/parity/surfaces.ts` was written to make
18
+ * visible. Assembling it here means the surfaces cannot disagree about what an
19
+ * assessment ask is, and a rule added once lands everywhere.
20
+ *
21
+ * THE ORDER IS THE DESIGN, not an optimisation detail. `isProjectAssessmentGoal`
22
+ * is a pure regex over the goal and runs FIRST: for every ordinary turn — the
23
+ * overwhelming majority — this function does no filesystem work at all and returns
24
+ * an empty block, so such a turn is byte-identical to one from a build without any
25
+ * of these modules. Only once a turn IS an assessment ask does it read the project
26
+ * directory.
27
+ *
28
+ * BEST-EFFORT BY CONTRACT, like the modules it composes. A missing/unreadable
29
+ * workspace, or a project with nothing discoverable, yields the rules block alone:
30
+ * the protocol still applies, and no turn is ever broken by a discovery failure.
31
+ */
32
+ import { assessmentProtocolBlock, isProjectAssessmentGoal } from './assessment-protocol.js';
33
+ import { buildSelfCheckBlock, readProjectSelfChecks } from './self-check-discovery.js';
34
+ import { buildPerfProbeBlock, detectPerfProbeInput } from './perf-probe.js';
35
+ /** The empty result — also what a non-assessment ask returns, by value. */
36
+ const NOT_ASSESSMENT = { isAssessment: false, block: '', selfChecks: 0, perfProbes: false };
37
+ /**
38
+ * Build the assessment section for one turn.
39
+ *
40
+ * @param goal the user's ask, verbatim (the detector reads it, so do not rewrite it first)
41
+ * @param dir the directory the turn is scoped to (the project being assessed)
42
+ * @param opts.facts machine facts, injectable for tests
43
+ */
44
+ export function buildAssessmentTurnContext(goal, dir, opts = {}) {
45
+ // The gate first: a non-assessment ask must not touch the filesystem.
46
+ if (!isProjectAssessmentGoal(goal))
47
+ return { ...NOT_ASSESSMENT };
48
+ let selfChecksBlock = '';
49
+ let selfCheckCount = 0;
50
+ try {
51
+ const checks = readProjectSelfChecks(dir);
52
+ selfCheckCount = checks.length;
53
+ selfChecksBlock = buildSelfCheckBlock(checks);
54
+ }
55
+ catch {
56
+ // Discovery is best-effort: the rules still apply without it.
57
+ }
58
+ let perfBlock = '';
59
+ try {
60
+ perfBlock = buildPerfProbeBlock(detectPerfProbeInput(dir, opts.facts));
61
+ }
62
+ catch {
63
+ // A probe section that cannot be detected is simply not offered.
64
+ }
65
+ const section = [selfChecksBlock.trim(), perfBlock.trim()].filter(Boolean).join('\n\n');
66
+ const block = assessmentProtocolBlock(goal, { selfChecks: section });
67
+ if (block === '')
68
+ return { ...NOT_ASSESSMENT };
69
+ return { isAssessment: true, block, selfChecks: selfCheckCount, perfProbes: perfBlock.trim() !== '' };
70
+ }
71
+ //# sourceMappingURL=assessment-turn-context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assessment-turn-context.js","sourceRoot":"","sources":["../../src/learning/assessment-turn-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,uBAAuB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAC5F,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AACvF,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAe5E,2EAA2E;AAC3E,MAAM,cAAc,GAA0B,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AAEnH;;;;;;GAMG;AACH,MAAM,UAAU,0BAA0B,CACxC,IAAY,EACZ,GAAW,EACX,OAAiC,EAAE;IAEnC,sEAAsE;IACtE,IAAI,CAAC,uBAAuB,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAEjE,IAAI,eAAe,GAAG,EAAE,CAAC;IACzB,IAAI,cAAc,GAAG,CAAC,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;QAC1C,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC;QAC/B,eAAe,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,8DAA8D;IAChE,CAAC;IAED,IAAI,SAAS,GAAG,EAAE,CAAC;IACnB,IAAI,CAAC;QACH,SAAS,GAAG,mBAAmB,CAAC,oBAAoB,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,iEAAiE;IACnE,CAAC;IAED,MAAM,OAAO,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,EAAE,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxF,MAAM,KAAK,GAAG,uBAAuB,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC;IACrE,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/C,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,SAAS,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;AACxG,CAAC"}
@@ -17,7 +17,10 @@
17
17
  * WALL-CLOCK TIME each cooling one frees up (a wait length is unactionable;
18
18
  * "free at 18:42" is something a person can plan around);
19
19
  * 3. what the system itself is doing about it (routing to an untried model,
20
- * or waiting for a window) — stated as the system's job, not the user's;
20
+ * or waiting for a window) — stated as the system's job, not the user's,
21
+ * and NEVER a promise it cannot keep: under a HELD pin nothing else is
22
+ * tried by design, so the report says that instead of "an untried model
23
+ * comes next automatically" (see `pinnedHeld`);
21
24
  * 4. the concrete levers only the user can pull: recharge/replace a rejected
22
25
  * credential, knowingly accept a weaker model, or narrow the ask.
23
26
  *
@@ -78,6 +81,26 @@ export interface ExhaustionInput {
78
81
  * says what releasing it would actually mean.
79
82
  */
80
83
  pinnedModel?: string;
84
+ /**
85
+ * True when that pin is HELD — the named model is the only one allowed to
86
+ * serve this turn, so no other model will be tried, now or on the next
87
+ * attempt.
88
+ *
89
+ * WHY THIS IS A SEPARATE INPUT FROM `pinnedModel`, and the bug it fixes. A pin
90
+ * is a contract about which model runs, and it is now the DEFAULT for a named
91
+ * pair — so the common case of a failed pinned turn is "stopped on purpose",
92
+ * not "ran out of pool". Measured on the real CLI (2026-10-16, model pinned to
93
+ * a pair the provider does not serve): the report still said *"This was a
94
+ * routing gap, not a shortage: only 1 of 5 eligible models were actually
95
+ * tried. The next attempt routes to an untried model automatically — you do
96
+ * not need to trigger anything."* Every clause of that is false while the pin
97
+ * holds. The walk stopped after one model because the USER's own contract
98
+ * forbade the other four, so it is neither a pool gap nor a shortage, and
99
+ * nothing at all happens next until the pin is released. Promising a silent
100
+ * automatic switch is the worst possible wording here: it tells the user to
101
+ * wait for a retry that the same run will refuse to perform.
102
+ */
103
+ pinnedHeld?: boolean;
81
104
  /**
82
105
  * The underlying failure line, when there is one (e.g. the provider's own
83
106
  * rejection text). Rendered as a `Reason:` line so a specific, actionable
@@ -1 +1 @@
1
- {"version":3,"file":"exhaustion-report.d.ts","sourceRoot":"","sources":["../../src/learning/exhaustion-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH,4DAA4D;AAC5D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,gFAAgF;AAChF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACnC,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,cAAc,GAAG,QAAQ,CAAC;IACtD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kFAAkF;IAClF,WAAW,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE,kEAAkE;IAClE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,oDAAoD;AACpD,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBxD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,eAAe,GAAG,gBAAgB,CAyJ9E;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAQjF"}
1
+ {"version":3,"file":"exhaustion-report.d.ts","sourceRoot":"","sources":["../../src/learning/exhaustion-report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,4DAA4D;AAC5D,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,+EAA+E;IAC/E,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,gFAAgF;AAChF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAC9B,UAAU,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACnC,qFAAqF;IACrF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;;OAUG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;;;;;;;;OAkBG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,cAAc,GAAG,QAAQ,CAAC;IACtD,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,MAAM,CAAC;IACjB,4EAA4E;IAC5E,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,kFAAkF;IAClF,WAAW,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACxE,kEAAkE;IAClE,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,2DAA2D;IAC3D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,UAAU,EAAE,OAAO,CAAC;IACpB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,oDAAoD;AACpD,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAIlD;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAuBxD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,eAAe,GAAG,gBAAgB,CAoK9E;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAQjF"}
@@ -17,7 +17,10 @@
17
17
  * WALL-CLOCK TIME each cooling one frees up (a wait length is unactionable;
18
18
  * "free at 18:42" is something a person can plan around);
19
19
  * 3. what the system itself is doing about it (routing to an untried model,
20
- * or waiting for a window) — stated as the system's job, not the user's;
20
+ * or waiting for a window) — stated as the system's job, not the user's,
21
+ * and NEVER a promise it cannot keep: under a HELD pin nothing else is
22
+ * tried by design, so the report says that instead of "an untried model
23
+ * comes next automatically" (see `pinnedHeld`);
21
24
  * 4. the concrete levers only the user can pull: recharge/replace a rejected
22
25
  * credential, knowingly accept a weaker model, or narrow the ask.
23
26
  *
@@ -117,7 +120,11 @@ export function buildExhaustionReport(input) {
117
120
  // models remained untouched. Presenting that as an outage is the dishonesty
118
121
  // the user called out when a healthy pool sat unused behind "no model
119
122
  // available".
120
- const routingGap = poolMeasured && triedAttempts.length > 0 && poolSize > triedAttempts.length;
123
+ // A held pin is NOT a routing gap: the untried models were left alone because
124
+ // the caller's pin forbids them, not because the walk fell short. Reporting it
125
+ // as a gap would also promise the automatic next attempt that the pin blocks.
126
+ const pinHeld = input.pinnedHeld === true;
127
+ const routingGap = !pinHeld && poolMeasured && triedAttempts.length > 0 && poolSize > triedAttempts.length;
121
128
  const emptyPool = poolMeasured && poolSize === 0;
122
129
  const parts = [];
123
130
  const attemptCount = triedAttempts.length;
@@ -161,7 +168,10 @@ export function buildExhaustionReport(input) {
161
168
  }
162
169
  // ── What the SYSTEM is doing (never a question to the user) ──────────────
163
170
  parts.push('');
164
- if (routingGap) {
171
+ if (pinHeld) {
172
+ parts.push(`Nothing else will be tried while the pin holds: ${input.pinnedModel ? input.pinnedModel : 'the model you named'} is the only one that may serve this run, so this is a deliberate stop and not a model shortage.`);
173
+ }
174
+ else if (routingGap) {
165
175
  parts.push(`This was a routing gap, not a shortage: only ${attemptCount} of ${poolSize} eligible models were actually tried. The next attempt routes to an untried model automatically — you do not need to trigger anything.`);
166
176
  }
167
177
  else if (emptyPool) {
@@ -194,9 +204,11 @@ export function buildExhaustionReport(input) {
194
204
  }
195
205
  options.push({
196
206
  code: 'weaker-model',
197
- text: input.pinnedModel
198
- ? `You pinned ${input.pinnedModel}, so nothing was run on a weaker model — say so explicitly if you would rather allow a weaker or cheaper one for this task.`
199
- : 'Allow a weaker or cheaper model for this task and accept that its answer may need more checking.',
207
+ text: pinHeld
208
+ ? `Release the pin to let another model answer — set NUVIRA_STRICT_MODEL=0 on the CLI, or turn the chat's lock off in the dashboard. Until you do, nothing else is tried, by design.`
209
+ : input.pinnedModel
210
+ ? `You pinned ${input.pinnedModel}, so nothing was run on a weaker model — say so explicitly if you would rather allow a weaker or cheaper one for this task.`
211
+ : 'Allow a weaker or cheaper model for this task and accept that its answer may need more checking.',
200
212
  });
201
213
  options.push({
202
214
  code: 'narrow',