@latysh-development/monolith 0.0.0-stage → 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +132 -2
  3. package/dist/brief/cli.d.ts +30 -0
  4. package/dist/brief/cli.d.ts.map +1 -0
  5. package/dist/brief/cli.js +85 -0
  6. package/dist/brief/collect.d.ts +17 -0
  7. package/dist/brief/collect.d.ts.map +1 -0
  8. package/dist/brief/collect.js +302 -0
  9. package/dist/brief/config.d.ts +40 -0
  10. package/dist/brief/config.d.ts.map +1 -0
  11. package/dist/brief/config.js +85 -0
  12. package/dist/brief/constants.d.ts +10 -0
  13. package/dist/brief/constants.d.ts.map +1 -0
  14. package/dist/brief/constants.js +9 -0
  15. package/dist/brief/docs.d.ts +53 -0
  16. package/dist/brief/docs.d.ts.map +1 -0
  17. package/dist/brief/docs.js +229 -0
  18. package/dist/brief/freshness.d.ts +104 -0
  19. package/dist/brief/freshness.d.ts.map +1 -0
  20. package/dist/brief/freshness.js +263 -0
  21. package/dist/brief/git-signals.d.ts +17 -0
  22. package/dist/brief/git-signals.d.ts.map +1 -0
  23. package/dist/brief/git-signals.js +101 -0
  24. package/dist/brief/index.d.ts +11 -0
  25. package/dist/brief/index.d.ts.map +1 -0
  26. package/dist/brief/index.js +5 -0
  27. package/dist/brief/reconcile.d.ts +75 -0
  28. package/dist/brief/reconcile.d.ts.map +1 -0
  29. package/dist/brief/reconcile.js +259 -0
  30. package/dist/brief/render.d.ts +60 -0
  31. package/dist/brief/render.d.ts.map +1 -0
  32. package/dist/brief/render.js +407 -0
  33. package/dist/brief/sanitize.d.ts +38 -0
  34. package/dist/brief/sanitize.d.ts.map +1 -0
  35. package/dist/brief/sanitize.js +48 -0
  36. package/dist/brief/selectors.d.ts +36 -0
  37. package/dist/brief/selectors.d.ts.map +1 -0
  38. package/dist/brief/selectors.js +75 -0
  39. package/dist/brief/story.d.ts +18 -0
  40. package/dist/brief/story.d.ts.map +1 -0
  41. package/dist/brief/story.js +59 -0
  42. package/dist/brief/types.d.ts +110 -0
  43. package/dist/brief/types.d.ts.map +1 -0
  44. package/dist/brief/types.js +11 -0
  45. package/dist/cli/index.d.ts +3 -0
  46. package/dist/cli/index.d.ts.map +1 -0
  47. package/dist/cli/index.js +166 -0
  48. package/dist/cli/init-args.d.ts +16 -0
  49. package/dist/cli/init-args.d.ts.map +1 -0
  50. package/dist/cli/init-args.js +24 -0
  51. package/dist/cli/ui-args.d.ts +23 -0
  52. package/dist/cli/ui-args.d.ts.map +1 -0
  53. package/dist/cli/ui-args.js +66 -0
  54. package/dist/cli/ui.d.ts +40 -0
  55. package/dist/cli/ui.d.ts.map +1 -0
  56. package/dist/cli/ui.js +180 -0
  57. package/dist/coordinatorium/checkpoint.d.ts +44 -0
  58. package/dist/coordinatorium/checkpoint.d.ts.map +1 -0
  59. package/dist/coordinatorium/checkpoint.js +124 -0
  60. package/dist/coordinatorium/cli.d.ts +39 -0
  61. package/dist/coordinatorium/cli.d.ts.map +1 -0
  62. package/dist/coordinatorium/cli.js +203 -0
  63. package/dist/coordinatorium/errors.d.ts +112 -0
  64. package/dist/coordinatorium/errors.d.ts.map +1 -0
  65. package/dist/coordinatorium/errors.js +145 -0
  66. package/dist/coordinatorium/index.d.ts +11 -0
  67. package/dist/coordinatorium/index.d.ts.map +1 -0
  68. package/dist/coordinatorium/index.js +5 -0
  69. package/dist/coordinatorium/lock.d.ts +187 -0
  70. package/dist/coordinatorium/lock.d.ts.map +1 -0
  71. package/dist/coordinatorium/lock.js +659 -0
  72. package/dist/coordinatorium/mission.d.ts +32 -0
  73. package/dist/coordinatorium/mission.d.ts.map +1 -0
  74. package/dist/coordinatorium/mission.js +87 -0
  75. package/dist/coordinatorium/state-keeper.d.ts +115 -0
  76. package/dist/coordinatorium/state-keeper.d.ts.map +1 -0
  77. package/dist/coordinatorium/state-keeper.js +396 -0
  78. package/dist/coordinatorium/types.d.ts +69 -0
  79. package/dist/coordinatorium/types.d.ts.map +1 -0
  80. package/dist/coordinatorium/types.js +27 -0
  81. package/dist/durable/assess.d.ts +105 -0
  82. package/dist/durable/assess.d.ts.map +1 -0
  83. package/dist/durable/assess.js +239 -0
  84. package/dist/durable/canonical.d.ts +25 -0
  85. package/dist/durable/canonical.d.ts.map +1 -0
  86. package/dist/durable/canonical.js +78 -0
  87. package/dist/durable/cli.d.ts +37 -0
  88. package/dist/durable/cli.d.ts.map +1 -0
  89. package/dist/durable/cli.js +141 -0
  90. package/dist/durable/errors.d.ts +188 -0
  91. package/dist/durable/errors.d.ts.map +1 -0
  92. package/dist/durable/errors.js +317 -0
  93. package/dist/durable/fs-store.d.ts +233 -0
  94. package/dist/durable/fs-store.d.ts.map +1 -0
  95. package/dist/durable/fs-store.js +1393 -0
  96. package/dist/durable/index.d.ts +20 -0
  97. package/dist/durable/index.d.ts.map +1 -0
  98. package/dist/durable/index.js +13 -0
  99. package/dist/durable/log.d.ts +33 -0
  100. package/dist/durable/log.d.ts.map +1 -0
  101. package/dist/durable/log.js +157 -0
  102. package/dist/durable/memory-store.d.ts +51 -0
  103. package/dist/durable/memory-store.d.ts.map +1 -0
  104. package/dist/durable/memory-store.js +302 -0
  105. package/dist/durable/projection.d.ts +35 -0
  106. package/dist/durable/projection.d.ts.map +1 -0
  107. package/dist/durable/projection.js +328 -0
  108. package/dist/durable/prune-check.d.ts +17 -0
  109. package/dist/durable/prune-check.d.ts.map +1 -0
  110. package/dist/durable/prune-check.js +45 -0
  111. package/dist/durable/register.d.ts +100 -0
  112. package/dist/durable/register.d.ts.map +1 -0
  113. package/dist/durable/register.js +532 -0
  114. package/dist/durable/retention.d.ts +49 -0
  115. package/dist/durable/retention.d.ts.map +1 -0
  116. package/dist/durable/retention.js +59 -0
  117. package/dist/durable/runtime.d.ts +497 -0
  118. package/dist/durable/runtime.d.ts.map +1 -0
  119. package/dist/durable/runtime.js +1271 -0
  120. package/dist/durable/seams.d.ts +40 -0
  121. package/dist/durable/seams.d.ts.map +1 -0
  122. package/dist/durable/seams.js +21 -0
  123. package/dist/durable/testing.d.ts +11 -0
  124. package/dist/durable/testing.d.ts.map +1 -0
  125. package/dist/durable/testing.js +25 -0
  126. package/dist/durable/types.d.ts +442 -0
  127. package/dist/durable/types.d.ts.map +1 -0
  128. package/dist/durable/types.js +75 -0
  129. package/dist/graph/builder.d.ts +11 -0
  130. package/dist/graph/builder.d.ts.map +1 -0
  131. package/dist/graph/builder.js +153 -0
  132. package/dist/graph/identity.d.ts +37 -0
  133. package/dist/graph/identity.d.ts.map +1 -0
  134. package/dist/graph/identity.js +46 -0
  135. package/dist/graph/index.d.ts +7 -0
  136. package/dist/graph/index.d.ts.map +1 -0
  137. package/dist/graph/index.js +3 -0
  138. package/dist/graph/resolver.d.ts +41 -0
  139. package/dist/graph/resolver.d.ts.map +1 -0
  140. package/dist/graph/resolver.js +36 -0
  141. package/dist/graph/types.d.ts +42 -0
  142. package/dist/graph/types.d.ts.map +1 -0
  143. package/dist/graph/types.js +1 -0
  144. package/dist/http/index.d.ts +5 -0
  145. package/dist/http/index.d.ts.map +1 -0
  146. package/dist/http/index.js +2 -0
  147. package/dist/http/server.d.ts +76 -0
  148. package/dist/http/server.d.ts.map +1 -0
  149. package/dist/http/server.js +195 -0
  150. package/dist/http/ui-assets.d.ts +22 -0
  151. package/dist/http/ui-assets.d.ts.map +1 -0
  152. package/dist/http/ui-assets.js +100 -0
  153. package/dist/index.d.ts +31 -0
  154. package/dist/index.d.ts.map +1 -0
  155. package/dist/index.js +26 -0
  156. package/dist/init/index.d.ts +12 -0
  157. package/dist/init/index.d.ts.map +1 -0
  158. package/dist/init/index.js +90 -0
  159. package/dist/init/prompts.d.ts +3 -0
  160. package/dist/init/prompts.d.ts.map +1 -0
  161. package/dist/init/prompts.js +47 -0
  162. package/dist/init/scaffold.d.ts +25 -0
  163. package/dist/init/scaffold.d.ts.map +1 -0
  164. package/dist/init/scaffold.js +204 -0
  165. package/dist/init/types.d.ts +14 -0
  166. package/dist/init/types.d.ts.map +1 -0
  167. package/dist/init/types.js +1 -0
  168. package/dist/readmodel/dashboard.d.ts +40 -0
  169. package/dist/readmodel/dashboard.d.ts.map +1 -0
  170. package/dist/readmodel/dashboard.js +236 -0
  171. package/dist/readmodel/index.d.ts +3 -0
  172. package/dist/readmodel/index.d.ts.map +1 -0
  173. package/dist/readmodel/index.js +1 -0
  174. package/dist/readmodel/types.d.ts +104 -0
  175. package/dist/readmodel/types.d.ts.map +1 -0
  176. package/dist/readmodel/types.js +15 -0
  177. package/dist/root/index.d.ts +179 -0
  178. package/dist/root/index.d.ts.map +1 -0
  179. package/dist/root/index.js +418 -0
  180. package/dist/root/safe-write.d.ts +268 -0
  181. package/dist/root/safe-write.d.ts.map +1 -0
  182. package/dist/root/safe-write.js +966 -0
  183. package/dist/root/write-artifacts.d.ts +20 -0
  184. package/dist/root/write-artifacts.d.ts.map +1 -0
  185. package/dist/root/write-artifacts.js +42 -0
  186. package/dist/scriptorium/compile.d.ts +4 -0
  187. package/dist/scriptorium/compile.d.ts.map +1 -0
  188. package/dist/scriptorium/compile.js +185 -0
  189. package/dist/scriptorium/frontmatter.d.ts +13 -0
  190. package/dist/scriptorium/frontmatter.d.ts.map +1 -0
  191. package/dist/scriptorium/frontmatter.js +90 -0
  192. package/dist/scriptorium/index.d.ts +3 -0
  193. package/dist/scriptorium/index.d.ts.map +1 -0
  194. package/dist/scriptorium/index.js +1 -0
  195. package/dist/scriptorium/markdown.d.ts +31 -0
  196. package/dist/scriptorium/markdown.d.ts.map +1 -0
  197. package/dist/scriptorium/markdown.js +88 -0
  198. package/dist/scriptorium/types.d.ts +78 -0
  199. package/dist/scriptorium/types.d.ts.map +1 -0
  200. package/dist/scriptorium/types.js +1 -0
  201. package/dist/types/enforcement.d.ts +11 -0
  202. package/dist/types/enforcement.d.ts.map +1 -0
  203. package/dist/types/enforcement.js +1 -0
  204. package/dist/types/integrity.d.ts +33 -0
  205. package/dist/types/integrity.d.ts.map +1 -0
  206. package/dist/types/integrity.js +1 -0
  207. package/dist/types/project-definition.d.ts +30 -0
  208. package/dist/types/project-definition.d.ts.map +1 -0
  209. package/dist/types/project-definition.js +1 -0
  210. package/dist/ui/assets/cosmic-glass-bg-Dwx47zPu.webp +0 -0
  211. package/dist/ui/assets/index-C4NhMaq7.js +28 -0
  212. package/dist/ui/assets/index-DMZ7ZvZY.css +1 -0
  213. package/dist/ui/index.html +13 -0
  214. package/dist/validate/index.d.ts +6 -0
  215. package/dist/validate/index.d.ts.map +1 -0
  216. package/dist/validate/index.js +214 -0
  217. package/dist/version.d.ts +2 -0
  218. package/dist/version.d.ts.map +1 -0
  219. package/dist/version.js +1 -0
  220. package/package.json +67 -4
  221. package/templates/.gitkeep +0 -0
  222. package/templates/default-instance/instruction/.cursorrules +53 -0
  223. package/templates/default-instance/instruction/.windsurfrules +53 -0
  224. package/templates/default-instance/instruction/CLAUDE.md +53 -0
  225. package/templates/default-instance/monolith/context/boot/HANDOFF.md +49 -0
  226. package/templates/default-instance/monolith/context/boot/WORK_SESSION.md +30 -0
  227. package/templates/default-instance/monolith/context/execution/current-state.md +30 -0
  228. package/templates/default-instance/monolith/context/maps/dependency-map.md +38 -0
  229. package/templates/default-instance/monolith/context/maps/project-map.md +85 -0
  230. package/templates/default-instance/monolith/context/maps/roadmap-index.md +41 -0
  231. package/templates/default-instance/monolith/context/maps/routing-map.md +147 -0
  232. package/templates/default-instance/monolith/context/maps/semantic-map.md +73 -0
  233. package/templates/default-instance/monolith/context/models/model-registry.md +37 -0
  234. package/templates/default-instance/monolith/context/models/privacy-classification.md +35 -0
  235. package/templates/default-instance/monolith/context/templates/plan-template.md +56 -0
  236. package/templates/default-instance/monolith/governance/README.md +29 -0
  237. package/templates/default-instance/monolith/governance/RULE_SCHEMA.md +58 -0
  238. package/templates/default-instance/monolith/learning/INDEX.md +48 -0
  239. package/templates/default-instance/monolith/learning/injection-map.md +49 -0
  240. package/templates/default-instance/monolith/learning/taxonomy.md +30 -0
  241. package/templates/default-instance/monolith/memory/errors/README.md +26 -0
  242. package/templates/default-instance/monolith/memory/errors/SCHEMA.md +47 -0
  243. package/templates/default-instance/monolith/memory/errors/TAXONOMY.md +27 -0
  244. package/templates/default-instance/monolith/memory/long-term/architecture-principles.md +31 -0
  245. package/templates/default-instance/monolith/memory/long-term/decisions.md +36 -0
  246. package/templates/default-instance/monolith/memory/long-term/execution-history.md +20 -0
  247. package/templates/default-instance/monolith/memory/long-term/tech-debt.md +25 -0
  248. package/templates/default-instance/monolith/memory/working/active.md +41 -0
  249. package/templates/default-instance/monolith/memory/working/governance-result.md +0 -0
  250. package/templates/default-instance/monolith/memory/working/integrity-result.md +0 -0
  251. package/templates/default-instance/monolith/memory/working/story-index.md +28 -0
  252. package/templates/default-instance/monolith/protocols/boot/boot-sequence.md +59 -0
  253. package/templates/default-instance/monolith/protocols/cognition/cognitive-modes.md +90 -0
  254. package/templates/default-instance/monolith/protocols/cognition/dry-run.md +56 -0
  255. package/templates/default-instance/monolith/protocols/cognition/execution-trace-format.md +52 -0
  256. package/templates/default-instance/monolith/protocols/cognition/semantic-planning.md +51 -0
  257. package/templates/default-instance/monolith/protocols/execution/hybrid-execution.md +37 -0
  258. package/templates/default-instance/monolith/protocols/execution/local-llm-governance.md +42 -0
  259. package/templates/default-instance/monolith/protocols/governance/command-policy.md +51 -0
  260. package/templates/default-instance/monolith/protocols/governance/core-invariants.md +40 -0
  261. package/templates/default-instance/monolith/protocols/governance/memory-governance.md +54 -0
  262. package/templates/default-instance/monolith/protocols/governance/metadata-schema.md +62 -0
  263. package/templates/default-instance/monolith/protocols/governance/skills.md +53 -0
  264. package/templates/default-instance/monolith/protocols/governance/work-session.md +46 -0
  265. package/templates/default-instance/monolith/skills/INDEX.md +28 -0
  266. package/templates/default-instance/monolith/skills/current-status/SKILL.md +47 -0
  267. package/templates/default-instance/monolith/skills/finalize-story/SKILL.md +86 -0
  268. package/templates/default-instance/monolith/skills/global-status/SKILL.md +56 -0
  269. package/templates/default-instance/monolith/skills/self-improvement/SKILL.md +77 -0
  270. package/templates/default-instance/monolith/state.json +11 -0
  271. package/templates/default-instance/monolith/tests/INDEX.md +57 -0
  272. package/templates/default-instance/monolith/tests/scenarios/architecture-review.md +32 -0
  273. package/templates/default-instance/monolith/tests/scenarios/debug-failure.md +32 -0
  274. package/templates/default-instance/monolith/tests/scenarios/dry-run-activation.md +33 -0
  275. package/templates/default-instance/monolith/tests/scenarios/execution-trace-verification.md +31 -0
  276. package/templates/default-instance/monolith/tests/scenarios/finalize-story.md +35 -0
  277. package/templates/default-instance/monolith/tests/scenarios/implement-feature.md +36 -0
  278. package/templates/default-instance/monolith/tests/scenarios/local-llm-delegation.md +31 -0
  279. package/templates/default-instance/monolith/tests/scenarios/planning-request.md +32 -0
  280. package/templates/default-instance/monolith/tests/scenarios/sensitive-context-task.md +30 -0
  281. package/templates/default-instance/monolith/tests/scenarios/validator-verification.md +33 -0
  282. package/templates/default-instance/monolith/tests/validation/expected-behavior.md +70 -0
  283. package/templates/default-instance/monolith/tests/validators/INDEX.md +17 -0
  284. package/templates/default-instance/monolith/tests/validators/delegation-semantics.md +22 -0
  285. package/templates/default-instance/monolith/tests/validators/mode-consistency.md +25 -0
  286. package/templates/default-instance/monolith/tests/validators/privacy-routing.md +23 -0
  287. package/templates/default-instance/monolith/tests/validators/protocol-references.md +27 -0
  288. package/templates/default-instance/monolith/tests/validators/routing-integrity.md +30 -0
  289. package/templates/default-instance/projectroot/AGENTS.md +107 -0
  290. package/templates/default-instance/projectroot/monolith.config.json +32 -0
  291. package/templates/default-instance/projectroot/project.definition.mjs.template +41 -0
@@ -0,0 +1,259 @@
1
+ /**
2
+ * State Reconciliation Report (SELF-AWARENESS-002).
3
+ *
4
+ * SELF-AWARENESS-001 says *whether* the recorded state looks outdated. This
5
+ * module says *what* the evidence is and *what a human should check*. It is
6
+ * pure: it takes the same `FreshnessEvidence` / `FreshnessResult` that
7
+ * `brief` already computed, reads nothing and writes nothing.
8
+ *
9
+ * Two rules shape every line of the report:
10
+ * - A git commit is not evidence that a work item is complete, and a work-item
11
+ * id in a commit subject is not evidence that its recorded status is right.
12
+ * The report therefore only ever says "referenced" and "not mentioned",
13
+ * never "done" or "missing from the roadmap because it was finished".
14
+ * - Recommendations are things for a person to verify or decide. Nothing here
15
+ * edits a document or concludes anything on the person's behalf.
16
+ *
17
+ * Findings are graded:
18
+ * confirmed a concrete, checkable discrepancy (documents contradict each other,
19
+ * or git names a work item that no state document mentions)
20
+ * suspected something that may be a discrepancy but cannot be shown from the data
21
+ * unknown the evidence needed to decide is missing (no git, truncated history, ...)
22
+ */
23
+ import { extractWorkItemIds, mentionsId, } from './freshness.js';
24
+ import { sanitizeSingleLine as san } from './sanitize.js';
25
+ export const MAX_COMMITS_PER_ITEM = 3;
26
+ const MAX_LISTED_ITEMS = 10;
27
+ const MAX_SUBJECT_CHARS = 72;
28
+ const DOC_ORDER = ['active.md', 'roadmap-index.md', 'story-index.md', 'HANDOFF.md'];
29
+ function short(sha) {
30
+ return sha.slice(0, 7);
31
+ }
32
+ function clip(s) {
33
+ return s.length <= MAX_SUBJECT_CHARS ? s : `${s.slice(0, MAX_SUBJECT_CHARS - 1)}…`;
34
+ }
35
+ function commitLine(c) {
36
+ return `${short(c.sha)} ${clip(c.subject)}`;
37
+ }
38
+ export function reconcile(ev, result) {
39
+ const findings = [];
40
+ const reviewReasons = new Map();
41
+ const actions = [];
42
+ const limitations = [
43
+ 'A commit is not evidence that a work item is complete; an id in a commit subject does not show its recorded status is correct.',
44
+ ];
45
+ const pathOf = (name) => [...ev.stateFiles].find((f) => f === name || f.endsWith(`/${name}`)) ?? name;
46
+ const review = (name, reason) => {
47
+ const path = pathOf(name);
48
+ const list = reviewReasons.get(path) ?? [];
49
+ if (!list.includes(reason))
50
+ list.push(reason);
51
+ reviewReasons.set(path, list);
52
+ };
53
+ // 1. Contradictions between the state documents — need no git.
54
+ for (const r of result.reasons) {
55
+ if (r.code !== 'STATE_CONTRADICTION')
56
+ continue;
57
+ const docs = r.documents ?? [];
58
+ findings.push({ kind: 'confirmed', code: 'STATE_CONTRADICTION', summary: r.message, evidence: docs });
59
+ for (const d of docs)
60
+ review(d, 'contradicts another state document');
61
+ actions.push(`Decide which state document is correct: ${r.message}`);
62
+ }
63
+ // 2. Git-derived evidence.
64
+ const untrackedWork = [];
65
+ let mentionedWork = [];
66
+ if (ev.git.status === 'unavailable') {
67
+ findings.push({ kind: 'unknown', code: 'GIT_UNAVAILABLE', summary: reasonMessage(result, 'GIT_UNAVAILABLE'), evidence: [] });
68
+ actions.push('Run this command from a git checkout (git must be installed) to compare the state documents with history.');
69
+ limitations.push('Git is unavailable: only contradictions between the state documents can be detected.');
70
+ }
71
+ else if (ev.git.lastStateUpdate === null) {
72
+ findings.push({ kind: 'unknown', code: 'STATE_NOT_IN_GIT', summary: reasonMessage(result, 'STATE_NOT_IN_GIT'), evidence: [] });
73
+ actions.push('Commit the state documents to establish a baseline, then re-run.');
74
+ limitations.push('No commit touches the state documents, so there is no baseline to compare history with.');
75
+ }
76
+ else {
77
+ const activity = ev.git.commitsSince.filter((c) => c.files.some((f) => !ev.stateFiles.has(f)));
78
+ const byId = new Map();
79
+ const unattributed = [];
80
+ for (const c of activity) {
81
+ const ids = extractWorkItemIds(c.subject);
82
+ if (ids.length === 0)
83
+ unattributed.push(c);
84
+ for (const id of ids)
85
+ byId.set(id, [...(byId.get(id) ?? []), c]);
86
+ }
87
+ const ids = [...byId.keys()].sort();
88
+ mentionedWork = ids.filter((id) => mentionsId(ev.recordedText, id));
89
+ for (const id of ids.filter((i) => !mentionsId(ev.recordedText, i))) {
90
+ const commits = byId.get(id) ?? [];
91
+ untrackedWork.push({
92
+ id,
93
+ commits: commits.slice(0, MAX_COMMITS_PER_ITEM).map((c) => ({ sha: c.sha, subject: c.subject })),
94
+ totalCommits: commits.length,
95
+ });
96
+ findings.push({
97
+ kind: 'confirmed',
98
+ code: 'UNRECORDED_WORK',
99
+ summary: `${id} is referenced by ${commits.length} commit(s) after the last state update; no state document mentions it.`,
100
+ evidence: commits.slice(0, MAX_COMMITS_PER_ITEM).map(commitLine),
101
+ });
102
+ }
103
+ if (untrackedWork.length > 0) {
104
+ review('roadmap-index.md', 'no entry for work items that git references');
105
+ review('HANDOFF.md', 'may not describe work items that git references');
106
+ if (ev.activeStory.kind !== 'ids')
107
+ review('active.md', 'confirm whether any of this work is current');
108
+ for (const u of untrackedWork.slice(0, MAX_LISTED_ITEMS)) {
109
+ actions.push(`Verify the status of ${u.id} and record it if appropriate (git references it; that does not show it is complete).`);
110
+ }
111
+ if (untrackedWork.length > MAX_LISTED_ITEMS) {
112
+ actions.push(`Verify the remaining ${untrackedWork.length - MAX_LISTED_ITEMS} untracked work item(s) listed above.`);
113
+ }
114
+ }
115
+ if (unattributed.length > 0) {
116
+ findings.push({
117
+ kind: 'suspected',
118
+ code: 'UNATTRIBUTED_ACTIVITY',
119
+ summary: `${unattributed.length} commit(s) after the last state update change project files without naming a work item; whether the state documents cover them cannot be determined.`,
120
+ evidence: unattributed.slice(0, MAX_COMMITS_PER_ITEM).map(commitLine),
121
+ });
122
+ actions.push(`Review the ${unattributed.length} commit(s) that name no work item and decide whether the recorded state covers them.`);
123
+ }
124
+ if (activity.length > 0 && ev.activeStory.kind === 'none') {
125
+ findings.push({
126
+ kind: 'suspected',
127
+ code: 'ACTIVITY_WITHOUT_ACTIVE_STORY',
128
+ summary: 'Git shows project activity after the last state update, but no active story is recorded.',
129
+ evidence: [],
130
+ });
131
+ review('active.md', 'no active story recorded while git shows later activity');
132
+ actions.push('Review the active story: confirm whether any work is current. No active story does not mean the project is complete.');
133
+ }
134
+ if (ev.git.truncated) {
135
+ findings.push({ kind: 'unknown', code: 'GIT_HISTORY_TRUNCATED', summary: reasonMessage(result, 'GIT_HISTORY_TRUNCATED'), evidence: [] });
136
+ limitations.push('Git history after the last state update was cut at the read limit; older commits are not examined.');
137
+ actions.push('Review the history since the last state update manually; this report covers only the newest commits.');
138
+ }
139
+ limitations.push('The last state update is the last commit touching a state document; uncommitted edits count for "mentioned" but not for that baseline.');
140
+ }
141
+ if (ev.activeStory.kind === 'unknown') {
142
+ findings.push({
143
+ kind: 'unknown',
144
+ code: 'ACTIVE_STORY_UNKNOWN',
145
+ summary: 'The active story could not be determined from active.md.',
146
+ evidence: [],
147
+ });
148
+ review('active.md', 'its current story could not be parsed');
149
+ }
150
+ const documents = [...reviewReasons.entries()]
151
+ .map(([path, reasons]) => ({ path, reasons }))
152
+ .sort((a, b) => docRank(a.path) - docRank(b.path));
153
+ return {
154
+ freshness: result.status,
155
+ lastStateUpdate: result.lastStateUpdate,
156
+ findings,
157
+ untrackedWork,
158
+ mentionedWork,
159
+ documents,
160
+ limitations,
161
+ actions,
162
+ };
163
+ }
164
+ function docRank(path) {
165
+ const i = DOC_ORDER.findIndex((n) => path === n || path.endsWith(`/${n}`));
166
+ return i === -1 ? DOC_ORDER.length : i;
167
+ }
168
+ function reasonMessage(result, code) {
169
+ return result.reasons.find((r) => r.code === code)?.message ?? code;
170
+ }
171
+ // ---------------------------------------------------------------------------
172
+ // Rendering
173
+ // ---------------------------------------------------------------------------
174
+ const TRUNCATION_MARKER_RESERVE = 100;
175
+ /**
176
+ * Deterministic, bounded text. The header (freshness) and the closing
177
+ * "No files were modified." are mandatory and never dropped; the sections in
178
+ * between are added in priority order while they fit, and an omission is
179
+ * always announced.
180
+ */
181
+ export function renderReconciliation(report, maxChars) {
182
+ const head = ['MONOLITH STATE RECONCILIATION', '', `Freshness: ${report.freshness}`];
183
+ if (report.lastStateUpdate) {
184
+ head.push(`Last state update: ${san(short(report.lastStateUpdate.sha))} (${san(report.lastStateUpdate.date.slice(0, 10))}, git)`);
185
+ }
186
+ const foot = '\nNo files were modified.\n';
187
+ const sections = [];
188
+ const bullets = (title, lines) => `\n${title}\n${lines.join('\n')}\n`;
189
+ const contradictions = report.findings.filter((f) => f.code === 'STATE_CONTRADICTION');
190
+ if (contradictions.length > 0) {
191
+ sections.push(bullets('Confirmed mismatches between state documents:', contradictions.map((f) => `- ${san(f.summary)}`)));
192
+ }
193
+ if (report.untrackedWork.length > 0) {
194
+ const lines = [];
195
+ for (const u of report.untrackedWork.slice(0, MAX_LISTED_ITEMS)) {
196
+ lines.push(`- ${u.id} (${u.totalCommits} commit(s) in git)`);
197
+ for (const c of u.commits)
198
+ lines.push(` ${san(commitLine(c))}`);
199
+ if (u.totalCommits > u.commits.length)
200
+ lines.push(` … and ${u.totalCommits - u.commits.length} more`);
201
+ }
202
+ if (report.untrackedWork.length > MAX_LISTED_ITEMS) {
203
+ lines.push(`- … and ${report.untrackedWork.length - MAX_LISTED_ITEMS} more work item(s)`);
204
+ }
205
+ sections.push(bullets('Untracked work items (referenced in git, mentioned in no state document):', lines));
206
+ }
207
+ for (const [kind, title] of [
208
+ ['suspected', 'Suspected mismatches (not confirmable from the data):'],
209
+ ['unknown', 'Unknown (evidence missing):'],
210
+ ]) {
211
+ const list = report.findings.filter((f) => f.kind === kind);
212
+ if (list.length === 0)
213
+ continue;
214
+ const lines = [];
215
+ for (const f of list) {
216
+ lines.push(`- ${san(f.summary)}`);
217
+ for (const e of f.evidence)
218
+ lines.push(` ${san(e)}`);
219
+ }
220
+ sections.push(bullets(title, lines));
221
+ }
222
+ if (report.documents.length > 0) {
223
+ const lines = [];
224
+ for (const d of report.documents)
225
+ lines.push(`- ${san(d.path)} — ${d.reasons.map(san).join('; ')}`);
226
+ sections.push(bullets('Documents requiring review:', lines));
227
+ }
228
+ if (report.findings.length === 0) {
229
+ sections.push('\nNo discrepancy was found in the available evidence. This is not a guarantee the state is correct.\n');
230
+ }
231
+ if (report.mentionedWork.length > 0) {
232
+ const shown = report.mentionedWork.slice(0, MAX_LISTED_ITEMS).join(', ');
233
+ const more = report.mentionedWork.length > MAX_LISTED_ITEMS ? ` and ${report.mentionedWork.length - MAX_LISTED_ITEMS} more` : '';
234
+ sections.push(`\nWork items in git that state documents mention: ${shown}${more}. Mentioned does not mean the recorded status is correct.\n`);
235
+ }
236
+ sections.push(bullets('Limitations:', report.limitations.map((l) => `- ${san(l)}`)));
237
+ if (report.actions.length > 0) {
238
+ sections.push(bullets('Suggested actions (for a person to decide; none is applied automatically):', report.actions.map((a, i) => `${i + 1}. ${san(a)}`)));
239
+ }
240
+ const mandatory = head.join('\n') + '\n' + foot;
241
+ let used = mandatory.length;
242
+ const kept = [];
243
+ let omitted = 0;
244
+ for (const s of sections) {
245
+ // Priority order: once a section is dropped, every later one is too. Room for the marker is always reserved.
246
+ if (omitted === 0 && used + s.length <= maxChars - TRUNCATION_MARKER_RESERVE) {
247
+ kept.push(s);
248
+ used += s.length;
249
+ }
250
+ else {
251
+ omitted++;
252
+ }
253
+ }
254
+ let body = kept.join('');
255
+ if (omitted > 0) {
256
+ body += `\n[truncated: ${omitted} section(s) omitted to fit --max-chars ${maxChars}]\n`;
257
+ }
258
+ return { text: head.join('\n') + '\n' + body + foot, truncated: omitted > 0 };
259
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * `render(model, maxChars)` — the Rendering stage of the brief pipeline.
3
+ *
4
+ * Pure and synchronous: same BriefModel + same maxChars always produces the
5
+ * byte-identical string (section 11 — determinism). No Date.now(), no
6
+ * random IDs, no locale-dependent sorting; every list collect() hands in is
7
+ * already in a fixed, stably-sorted order.
8
+ *
9
+ * Budget accounting (section 10) in two phases to avoid a circular
10
+ * dependency between "does P0 fit" and "what does the Completeness line
11
+ * say" (rule: no diagnostic/marker line may be added without being counted
12
+ * in the budget that decided what else fits):
13
+ *
14
+ * Phase 1 — build all P0 content (identity, State Keeper status,
15
+ * collect-time diagnostics, every active mission identifier, every
16
+ * mandatory protocol pointer) with NO budget limit — P0 is never
17
+ * truncated or hidden (rule 5/7). If P0 alone (plus the reserved,
18
+ * fixed-size Completeness line) exceeds maxChars, that is reported via
19
+ * BUDGET_EXCEEDED_BY_REQUIRED (which also states explicitly that P1–P3
20
+ * are skipped entirely as a result — review finding F-5) and nothing
21
+ * else is attempted.
22
+ *
23
+ * Phase 2 — whatever chars remain after P0 + the reserved Completeness
24
+ * line are handed to P1 (Checkpoints, then Story — Checkpoints first so
25
+ * a long Story can never silently starve "Next steps" out of the budget;
26
+ * review finding F-5), then P2, then P3, in that fixed order. Each
27
+ * section either fits whole, or (list sections) includes as many whole
28
+ * items as fit plus an explicit "N more omitted" marker, or (the Story
29
+ * excerpt) is field-truncated with an explicit `[truncated N chars]`
30
+ * marker, or — if not even that fits — falls back to a short, fixed-size
31
+ * local omission marker so a section can never disappear from the output
32
+ * without some local trace of its omission (review finding F-5; the only
33
+ * residual case where a section can still vanish with zero local marker
34
+ * is when `remaining` is too small even for that minimal marker, which
35
+ * is itself already covered by the global Completeness: INCOMPLETE
36
+ * signal). Every one of these outcomes is itself measured and subtracted
37
+ * from the remaining budget before the next section is attempted —
38
+ * nothing is added "for free" after the fact.
39
+ *
40
+ * Completeness contract (N-3): `Completeness: COMPLETE` means no
41
+ * *substantive data* was lost, not that every section heading is present.
42
+ * An optional section that has nothing to show (an empty list, rendered
43
+ * only as "(none)") and the static P3 pointer block may be dropped under a
44
+ * tight budget without flipping the result to INCOMPLETE — dropping them
45
+ * loses no information. A section that holds data is never dropped
46
+ * silently: it is shown whole, shown partially with an explicit marker, or
47
+ * replaced by a pointer-bearing omission marker, and either of the latter
48
+ * two forces INCOMPLETE. P0 is never dropped. All project-controlled
49
+ * strings, provenance pointers included, pass through
50
+ * `sanitizeSingleLine` (N-1).
51
+ */
52
+ import type { BriefModel } from './types.js';
53
+ export declare const DEFAULT_MAX_CHARS = 6000;
54
+ export type Completeness = 'COMPLETE' | 'INCOMPLETE';
55
+ export interface RenderResult {
56
+ text: string;
57
+ completeness: Completeness;
58
+ }
59
+ export declare function render(model: BriefModel, maxChars?: number): RenderResult;
60
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/brief/render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAsE,MAAM,YAAY,CAAC;AAYjH,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAGtC,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,YAAY,CAAC;AAErD,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,YAAY,CAAC;CAC5B;AAiVD,wBAAgB,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,GAAE,MAA0B,GAAG,YAAY,CAsE5F"}