@pukujan/create-modular-monolith 2.2.1 → 2.2.3

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 (30) hide show
  1. package/package.json +1 -1
  2. package/template/.cursor/rules/file-exchange-inbox.mdc +1 -1
  3. package/template/ARCHITECTURE_EXPORT_README.md +30 -0
  4. package/template/EXPORT_MANIFEST.json +74 -0
  5. package/template/NOTICE +2 -3
  6. package/template/README.md +1 -61
  7. package/template/backend/package.json +1 -1
  8. package/template/backend/src/modules/model-condenser/services/modelCondenser.service.js +36 -465
  9. package/template/backend/src/modules/model-condenser/tests/unit/modelCondenser.service.test.js +2 -3
  10. package/template/backend/src/shared/utils/consolidatedExport.js +155 -11
  11. package/template/backend/src/shared/utils/consolidatedExport.test.js +50 -0
  12. package/template/docs/README.md +0 -1
  13. package/template/docs/architecture/EVAL_AND_CI.md +68 -41
  14. package/template/docs/architecture/REPO_ARTIFACT_LAYOUT.md +57 -14
  15. package/template/docs/architecture/contracts/consolidatedExports.contract.md +14 -10
  16. package/template/docs/architecture/contracts/manifest.json +17 -0
  17. package/template/file-exchange/README.md +20 -15
  18. package/template/frontend/package.json +1 -1
  19. package/template/package.json +3 -3
  20. package/template/scripts/condense-all.mjs +52 -0
  21. package/template/scripts/condense-file-structure.mjs +19 -10
  22. package/template/scripts/condense-models.mjs +5 -3
  23. package/template/scripts/condense-prompts.mjs +13 -51
  24. package/template/scripts/consolidated-output.mjs +22 -10
  25. package/template/scripts/export-architecture-starter.mjs +389 -0
  26. package/template/scripts/lib/api-inventory.mjs +16 -61
  27. package/template/scripts/lib/repo-tree.mjs +26 -4
  28. package/template/scripts/sync-cli-template.mjs +44 -0
  29. package/template/scripts/write-pre-push-dev-log.mjs +1 -0
  30. package/template/file-exchange/exports/consolidated-models.json +0 -625
@@ -1,30 +1,174 @@
1
- import { mkdir, writeFile } from "fs/promises";
1
+ import { mkdir, readFile, writeFile } from "fs/promises";
2
2
  import { join } from "path";
3
+ import { formatExchangeTimestamp, normalizeExchangeStamp } from "./formatExchangeTimestamp.js";
3
4
 
4
- /** Consolidated deliverables live directly under file-exchange/exports/. */
5
+ /** Session exports and consolidated snapshots root. */
5
6
  export const CONSOLIDATED_EXPORT_DIR = "file-exchange/exports";
6
7
 
8
+ /** Folder suffix for consolidated audit bundles (matches file-exchange stamp convention). */
9
+ export const CONSOLIDATED_FOLDER_LABEL = "consolidated";
10
+
7
11
  export const CONSOLIDATED_FILENAMES = {
8
12
  models: "consolidated-models.json",
9
13
  prompts: "consolidated-prompts.json",
10
14
  fileStructure: "consolidated-file-structure.json"
11
15
  };
12
16
 
17
+ export const CONSOLIDATED_MANIFEST_FILENAME = "manifest.json";
18
+
19
+ const ENV_STAMP = "CONSOLIDATED_EXPORT_STAMP";
20
+
21
+ /**
22
+ * @param {string} [stamp]
23
+ * @param {string} [label]
24
+ * @returns {string} e.g. 2026-05-23_15-59-43Z_consolidated
25
+ */
26
+ export function consolidatedExportFolderName(stamp, label = CONSOLIDATED_FOLDER_LABEL) {
27
+ return `${normalizeExchangeStamp(stamp)}_${label}`;
28
+ }
29
+
30
+ /**
31
+ * Resolve or create a shared UTC stamp for one condense run (condense:all shares via env).
32
+ * @param {{ create?: boolean }} [options]
33
+ * @returns {string|null}
34
+ */
35
+ export function getConsolidatedExportStamp({ create = true } = {}) {
36
+ const fromEnv = process.env[ENV_STAMP];
37
+ if (fromEnv) {
38
+ return normalizeExchangeStamp(fromEnv);
39
+ }
40
+ if (!create) {
41
+ return null;
42
+ }
43
+ const stamp = formatExchangeTimestamp();
44
+ process.env[ENV_STAMP] = stamp;
45
+ return stamp;
46
+ }
47
+
48
+ /**
49
+ * Start a consolidated export session (sets CONSOLIDATED_EXPORT_STAMP).
50
+ * @param {{ stamp?: string, label?: string }} [options]
51
+ */
52
+ export function beginConsolidatedExportSession(options = {}) {
53
+ const stamp = options.stamp
54
+ ? normalizeExchangeStamp(options.stamp)
55
+ : getConsolidatedExportStamp({ create: true });
56
+ process.env[ENV_STAMP] = stamp;
57
+ const folderName = consolidatedExportFolderName(stamp, options.label ?? CONSOLIDATED_FOLDER_LABEL);
58
+ return {
59
+ stamp,
60
+ label: options.label ?? CONSOLIDATED_FOLDER_LABEL,
61
+ folderName,
62
+ exportDir: `${CONSOLIDATED_EXPORT_DIR}/${folderName}`
63
+ };
64
+ }
65
+
66
+ /**
67
+ * @param {string} repoRoot
68
+ * @param {string} stamp
69
+ * @param {string} [label]
70
+ * @returns {string} absolute path to dated export folder
71
+ */
72
+ export function resolveConsolidatedExportDir(repoRoot, stamp, label = CONSOLIDATED_FOLDER_LABEL) {
73
+ return join(repoRoot, CONSOLIDATED_EXPORT_DIR, consolidatedExportFolderName(stamp, label));
74
+ }
75
+
13
76
  /**
14
- * Write a consolidated JSON artifact to file-exchange/exports/.
77
+ * Write a consolidated JSON artifact to a dated export folder and refresh latest mirrors.
15
78
  * @param {string} repoRoot
16
79
  * @param {string} filename
17
80
  * @param {string} jsonText
18
- * @returns {Promise<string>} absolute path written
81
+ * @param {{ stamp?: string, label?: string, writeLatest?: boolean, condensedBy?: string }} [options]
82
+ * @returns {Promise<{ absolutePath: string, exportPath: string, datedExportDir: string, stamp: string, folderName: string }>}
19
83
  */
20
- export async function writeConsolidatedExport(repoRoot, filename, jsonText) {
21
- const dest = join(repoRoot, CONSOLIDATED_EXPORT_DIR, filename);
22
- await mkdir(join(repoRoot, CONSOLIDATED_EXPORT_DIR), { recursive: true });
23
- await writeFile(dest, jsonText, "utf8");
24
- return dest;
84
+ export async function writeConsolidatedExport(repoRoot, filename, jsonText, options = {}) {
85
+ const stamp = options.stamp ?? getConsolidatedExportStamp({ create: true });
86
+ const label = options.label ?? CONSOLIDATED_FOLDER_LABEL;
87
+ const folderName = consolidatedExportFolderName(stamp, label);
88
+ const datedDir = join(repoRoot, CONSOLIDATED_EXPORT_DIR, folderName);
89
+ const exportsRoot = join(repoRoot, CONSOLIDATED_EXPORT_DIR);
90
+
91
+ await mkdir(datedDir, { recursive: true });
92
+ await mkdir(exportsRoot, { recursive: true });
93
+
94
+ const absolutePath = join(datedDir, filename);
95
+ await writeFile(absolutePath, jsonText, "utf8");
96
+
97
+ if (options.writeLatest !== false) {
98
+ await writeFile(join(exportsRoot, filename), jsonText, "utf8");
99
+ }
100
+
101
+ if (options.condensedBy) {
102
+ await appendConsolidatedManifest(repoRoot, stamp, {
103
+ filename,
104
+ condensedBy: options.condensedBy,
105
+ label
106
+ });
107
+ }
108
+
109
+ return {
110
+ absolutePath,
111
+ exportPath: `${CONSOLIDATED_EXPORT_DIR}/${folderName}/${filename}`,
112
+ datedExportDir: `${CONSOLIDATED_EXPORT_DIR}/${folderName}`,
113
+ stamp,
114
+ folderName
115
+ };
116
+ }
117
+
118
+ /**
119
+ * @param {string} repoRoot
120
+ * @param {string} stamp
121
+ * @param {{ filename: string, condensedBy?: string, label?: string }} entry
122
+ */
123
+ export async function appendConsolidatedManifest(repoRoot, stamp, entry) {
124
+ const label = entry.label ?? CONSOLIDATED_FOLDER_LABEL;
125
+ const folderName = consolidatedExportFolderName(stamp, label);
126
+ const manifestPath = join(
127
+ repoRoot,
128
+ CONSOLIDATED_EXPORT_DIR,
129
+ folderName,
130
+ CONSOLIDATED_MANIFEST_FILENAME
131
+ );
132
+ const now = new Date().toISOString();
133
+
134
+ let manifest = {
135
+ stamp: normalizeExchangeStamp(stamp),
136
+ folder: folderName,
137
+ label,
138
+ startedAt: now,
139
+ updatedAt: now,
140
+ artifacts: []
141
+ };
142
+
143
+ try {
144
+ const raw = await readFile(manifestPath, "utf8");
145
+ manifest = JSON.parse(raw);
146
+ manifest.updatedAt = now;
147
+ if (!Array.isArray(manifest.artifacts)) {
148
+ manifest.artifacts = [];
149
+ }
150
+ } catch {
151
+ /* new manifest */
152
+ }
153
+
154
+ const existing = manifest.artifacts.findIndex((a) => a.filename === entry.filename);
155
+ const row = {
156
+ filename: entry.filename,
157
+ condensedBy: entry.condensedBy ?? null,
158
+ writtenAt: now
159
+ };
160
+ if (existing >= 0) {
161
+ manifest.artifacts[existing] = row;
162
+ } else {
163
+ manifest.artifacts.push(row);
164
+ }
165
+
166
+ await mkdir(join(repoRoot, CONSOLIDATED_EXPORT_DIR, folderName), { recursive: true });
167
+ await writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, "utf8");
168
+ return manifestPath;
25
169
  }
26
170
 
27
171
  /** @deprecated use writeConsolidatedExport */
28
- export async function mirrorConsolidatedExport(repoRoot, filename, jsonText) {
29
- return writeConsolidatedExport(repoRoot, filename, jsonText);
172
+ export async function mirrorConsolidatedExport(repoRoot, filename, jsonText, options = {}) {
173
+ return writeConsolidatedExport(repoRoot, filename, jsonText, options);
30
174
  }
@@ -0,0 +1,50 @@
1
+ import { test } from "node:test";
2
+ import assert from "node:assert/strict";
3
+ import { mkdtemp, readFile, rm, access } from "fs/promises";
4
+ import { join } from "path";
5
+ import { tmpdir } from "os";
6
+ import {
7
+ beginConsolidatedExportSession,
8
+ consolidatedExportFolderName,
9
+ writeConsolidatedExport,
10
+ CONSOLIDATED_MANIFEST_FILENAME
11
+ } from "./consolidatedExport.js";
12
+
13
+ test("writeConsolidatedExport writes dated folder and latest copy", async () => {
14
+ const repoRoot = await mkdtemp(join(tmpdir(), "consolidated-export-"));
15
+ delete process.env.CONSOLIDATED_EXPORT_STAMP;
16
+
17
+ try {
18
+ const session = beginConsolidatedExportSession({ stamp: "2026-05-23_15-59-43Z" });
19
+ assert.equal(session.folderName, "2026-05-23_15-59-43Z_consolidated");
20
+
21
+ const written = await writeConsolidatedExport(
22
+ repoRoot,
23
+ "consolidated-models.json",
24
+ '{"meta":{"condensedBy":"test"}}',
25
+ { stamp: session.stamp, condensedBy: "test" }
26
+ );
27
+
28
+ assert.ok(written.exportPath.includes("2026-05-23_15-59-43Z_consolidated/consolidated-models.json"));
29
+
30
+ await access(join(repoRoot, "file-exchange/exports/2026-05-23_15-59-43Z_consolidated/consolidated-models.json"));
31
+ await access(join(repoRoot, "file-exchange/exports/consolidated-models.json"));
32
+
33
+ const manifest = JSON.parse(
34
+ await readFile(
35
+ join(
36
+ repoRoot,
37
+ "file-exchange/exports",
38
+ consolidatedExportFolderName(session.stamp),
39
+ CONSOLIDATED_MANIFEST_FILENAME
40
+ ),
41
+ "utf8"
42
+ )
43
+ );
44
+ assert.equal(manifest.stamp, "2026-05-23_15-59-43Z");
45
+ assert.ok(manifest.artifacts.some((a) => a.filename === "consolidated-models.json"));
46
+ } finally {
47
+ await rm(repoRoot, { recursive: true, force: true });
48
+ delete process.env.CONSOLIDATED_EXPORT_STAMP;
49
+ }
50
+ });
@@ -11,7 +11,6 @@ This folder describes the **modular monolith platform starter** and how **archit
11
11
  | [Starter pack](./STARTER_PACK.md) | What ships in the repo, how to run it, and how to add modules |
12
12
  | [Architecture guardrails](./architecture/ARCHITECTURE_GUARDRAILS.md) | Module contracts, boundaries, naming, and how enforcement works |
13
13
  | [Module internal contract](./architecture/MODULE_INTERNAL_CONTRACT.md) | MVC layers, prompts, evals, tests inside each feature module |
14
- | [Evals, regression, and CI gates](./architecture/EVAL_AND_CI.md) | `test:ci`, GitHub Actions, optional per-case golden |
15
14
  | [Evals, regression, and CI gates](./architecture/EVAL_AND_CI.md) | Golden evals, `test:evals`, GitHub Actions gates |
16
15
  | [Publishing the CLI](./PUBLISHING.md) | Release `@pukujan/create-modular-monolith` to npm |
17
16
  | [Case Filing AI starter](./case-filing-ai/README.md) | Domain blueprint, module split, pipeline, guardrails, and DB schema |
@@ -1,79 +1,106 @@
1
1
  # Evals, regression, and CI gates
2
2
 
3
- Plain-language guide for **domain-agnostic** projects scaffolded from this template.
3
+ Plain-language guide to how this repo checks prompt and pipeline quality automatically.
4
4
 
5
5
  ---
6
6
 
7
7
  ## What is a “gate”?
8
8
 
9
- A **gate** is an automatic check that must pass before code is merged.
9
+ A **gate** is an automatic check that must pass before code is merged or published.
10
10
 
11
- | Gate | What it blocks |
12
- |------|----------------|
11
+ Think of it like airport security: if the check fails, you do not proceed until it is fixed.
12
+
13
+ | Gate (command) | What it blocks |
14
+ |----------------|----------------|
13
15
  | `npm run lint:contracts` | Broken contract paths in `manifest.json` |
14
- | `npm run lint:repo-artifacts` | Missing platform folders (file-exchange, dev-logs, ) |
15
- | `npm run lint:architecture` | Module boundary / layer / API doc violations |
16
- | `npm test` | Unit/integration failures |
17
- | `npm run test:evals` | Module `evals/runners/*.eval.mjs` failures |
16
+ | `npm run lint:repo-artifacts` | Missing required folders/files (including golden CI slice) |
17
+ | `npm run lint:architecture` | Module boundary/layer/API doc violations |
18
+ | `npm test` | Unit/integration test failures |
19
+ | `npm run test:evals` | Golden regression failures (offline, no API key) |
18
20
 
19
- GitHub Actions runs these on push/PR (see `.github/workflows/ci.yml`). Locally: **`npm run test:ci`**.
21
+ GitHub Actions runs these on every push/PR to `main` (see `.github/workflows/ci.yml`).
20
22
 
21
23
  ---
22
24
 
23
25
  ## What is “eval / regression”?
24
26
 
25
- **Eval** = automated check that output meets expectations.
27
+ **Eval** = compare actual AI output to **expected** (golden) JSON.
26
28
 
27
- **Regression** = re-run evals after a change to catch quality going **down**.
29
+ **Regression** = re-run that comparison after you change prompts or code, to see if quality got worse.
28
30
 
29
- ### Golden data is per domain case — not universal
31
+ ```text
32
+ Fixture output (or live batch output)
33
+
34
+ evalRunner.evalDocument()
35
+
36
+ Compare to evals/golden/case_001/doc_NNN.expected.json
37
+
38
+ Scores + pass | partial | fail
39
+ ```
30
40
 
31
- Every product case is different (different users, documents, rules). You **do not** ship one golden dataset for all future cases.
41
+ This repo uses **golden files** under `evals/golden/case_001/`:
32
42
 
33
- | Pattern | When to use |
34
- |---------|-------------|
35
- | **Module example evals** | Shipped in `_reference` smoke tests, no API keys |
36
- | **Optional `evals/golden/{caseId}/`** | When **you** curate expected JSON for one fixed regression case |
37
- | **Live runs only** | New cases with no golden yet process, review, optionally add golden later |
43
+ | File | Purpose |
44
+ |------|---------|
45
+ | `doc_001.expected.json` | What doc 1 extraction should look like |
46
+ | `after_doc_001.expected.json` | Case snapshot after doc 1 |
47
+ | `negative_guardrails.expected.json` | Rules that must never appear in output |
48
+ | `case_001.golden-dataset.json` | Manifest (checkpoints, version) |
38
49
 
39
- Golden answers the question: *“On **this** known fixture, did we get worse than last time?”*
40
- Not: *“We already know the truth for every new case.”*
50
+ A **minimal golden slice** is committed for CI. Full synthetic case data can be ingested via:
41
51
 
42
- When you add a domain module (`npm run new:module`), add `evals/runners/` and optional `evals/golden/` for cases you control.
52
+ ```bash
53
+ npm run import:file-exchange -- <bundle>
54
+ npm run ingest:golden-expected
55
+ ```
43
56
 
44
57
  ---
45
58
 
46
- ## Trace IDs (observability)
47
-
48
- Use `backend/src/shared/utils/traceId.js` in long-running workflows:
59
+ ## Running evals locally
49
60
 
50
- ```js
51
- import { createTraceId, docTraceId } from "../shared/utils/traceId.js";
61
+ ```bash
62
+ # All module eval runners (offline for case-filing-ai)
63
+ npm run test:evals
52
64
 
53
- const batchTraceId = createTraceId("batch_my-job");
54
- const traceId = docTraceId(batchTraceId, 1);
65
+ # Case Filing AI only
66
+ npm run test:evals -- case-filing-ai
55
67
  ```
56
68
 
57
- Log both IDs in JSONL or structured logs so agents and humans can correlate steps. Plug the same IDs into Langfuse/OpenTelemetry later if needed.
69
+ `golden-regression.eval.mjs` uses test fixtures **no OpenRouter key required**.
70
+
71
+ Live batch evals still run when you process uploads; reports land in `data/.../batches/batch-NNN/evals/`.
58
72
 
59
73
  ---
60
74
 
61
- ## CI workflow
75
+ ## Trace IDs (observability)
62
76
 
63
- `.github/workflows/ci.yml`:
77
+ Each batch gets `batchTraceId`; each document gets `traceId` in:
64
78
 
65
- 1. Install backend + frontend
66
- 2. `lint:contracts` · `lint:repo-artifacts` · `lint:architecture`
67
- 3. `npm test` · `npm run test:evals`
79
+ - `processing-log.jsonl` entries
80
+ - Document output JSON
81
+
82
+ Use these to correlate logs, eval reports, and future external tracing (Langfuse, etc.).
68
83
 
69
84
  ---
70
85
 
71
- ## Adding domain evals
86
+ ## Schema validation
72
87
 
73
- ```bash
74
- npm run new:module -- billing --label "Billing"
75
- # Add backend/src/modules/billing/evals/runners/my-check.eval.mjs
76
- npm run test:evals -- billing
77
- ```
88
+ Master prompt JSON is validated against:
89
+
90
+ - `schemas/master-output.v1.schema.json` (v1, compact, v2)
91
+ - `schemas/master-output.v001.schema.json` (v001)
92
+
93
+ Invalid output triggers a schema-aware retry before failing the document.
94
+
95
+ ---
96
+
97
+ ## CI workflow
98
+
99
+ `.github/workflows/ci.yml` runs on push/PR:
100
+
101
+ 1. Install backend + frontend deps
102
+ 2. `lint:contracts` · `lint:repo-artifacts` · `lint:architecture`
103
+ 3. `npm test`
104
+ 4. `npm run test:evals`
78
105
 
79
- See [MODULE_INTERNAL_CONTRACT.md](./MODULE_INTERNAL_CONTRACT.md) for colocated `prompts/` and `evals/`.
106
+ Or locally: `npm run test:ci` (same checks from repo root).
@@ -1,25 +1,48 @@
1
1
  # Repository artifact layout
2
2
 
3
- Canonical paths for platform artifacts and human↔agent exchange.
3
+ Canonical paths for runtime data, golden fixtures, and human↔agent exchange.
4
4
 
5
5
  ## Roots
6
6
 
7
- | Root | Writable at runtime | Purpose |
8
- |------|---------------------|---------|
9
- | `file-exchange/imports\|exports/` | Yes | Dated human↔agent handoff |
10
- | `work-log/dev-logs/human\|agent/` | Yes | Pre-push audit pairs |
11
- | `models/consolidated-*.json` | Yes | Mirror of `file-exchange/exports/consolidated-*.json` |
12
- | `work-log/handoffs/` | Yes | Session handoffs (markdown) |
13
- | `data/` | Yes | **Your** domain runtime data (gitignore by default) |
14
- | `evals/golden/{caseId}/` | Optional | Per-case regression fixtures when you add them |
7
+ | Root | Env override | Writable at runtime |
8
+ |------|----------------|---------------------|
9
+ | `data/case-filing-ai/batches/` | `CASE_FILING_BATCH_DIR` | Yes (pipeline) |
10
+ | `evals/golden/{caseId}/` | `GOLDEN_DATASET_DIR` | No (fixtures) |
11
+ | `data/court-rules/fixtures/` | | No |
12
+ | `eval-bundles/` | `EVAL_BUNDLE_ROOT_DIR` | Yes (export API) |
13
+ | `case-exports/` | `CASE_EXPORT_ROOT_DIR` | Yes (export API) |
14
+ | `file-exchange/imports\|exports/` | | Yes (human triage) |
15
+ | `work-log/dev-logs/human\|agent/` | — | Yes (pre-push audit) |
16
+ | `models/consolidated-*.json` | — | Yes (condenser mirror) |
17
+ | `work-log/` | — | Yes (docs only) |
18
+
19
+ ## Batch folder (`batches/batch-NNN/`)
20
+
21
+ ```text
22
+ uploads/
23
+ parsed-documents/doc-NNN/ # v2+ parsed cache
24
+ outputs/doc-NNN.json
25
+ evals/doc_NNN.eval-report.json
26
+ rule/
27
+ case-snapshot.json
28
+ processing-log.jsonl
29
+ ```
30
+
31
+ ## Golden (`evals/golden/case_001/`)
32
+
33
+ ```text
34
+ case_001.golden-dataset.json
35
+ doc_NNN.expected.json
36
+ parsed/doc-NNN/ # optional parse golden (v2)
37
+ ```
15
38
 
16
39
  ## File exchange
17
40
 
18
41
  Imports: `file-exchange/imports/{2026-05-23_15-59-43Z}/`
19
- Session exports: `file-exchange/exports/{stamp}/`
20
- Consolidated snapshots: `file-exchange/exports/consolidated-*.json`
42
+ Session exports: `file-exchange/exports/{stamp}_{label}/`
43
+ Consolidated snapshots: `file-exchange/exports/{stamp}_consolidated/` (+ latest `consolidated-*.json` at `exports/` root)
21
44
 
22
- See [file-exchange/README.md](../../file-exchange/README.md).
45
+ See [file-exchange/README.md](../../file-exchange/README.md) and [contracts/fileExchange.contract.md](./contracts/fileExchange.contract.md).
23
46
 
24
47
  ## Pre-push dev logs
25
48
 
@@ -28,6 +51,26 @@ work-log/dev-logs/human/{NNN}_{date}_{time}_dev-log_{slug}.md
28
51
  work-log/dev-logs/agent/{NNN}_{date}_{time}_dev-log-agent_{slug}.json
29
52
  ```
30
53
 
31
- ## Domain modules
54
+ `npm run dev-log:pre-push` — see [contracts/prePushDevLog.contract.md](./contracts/prePushDevLog.contract.md).
55
+
56
+ ## Consolidated exports
57
+
58
+ `npm run condense:all` → [contracts/consolidatedExports.contract.md](./contracts/consolidatedExports.contract.md).
59
+
60
+ ## Contracts
61
+
62
+ **Overview (start here):** [CONTRACTS_OVERVIEW.md](./CONTRACTS_OVERVIEW.md)
63
+ Manifest: [contracts/manifest.json](./contracts/manifest.json) · Changelog: [contracts/changelog.jsonl](./contracts/changelog.jsonl)
64
+
65
+ | Contract | Doc |
66
+ |----------|-----|
67
+ | File exchange | [fileExchange.contract.md](./contracts/fileExchange.contract.md) |
68
+ | Consolidated exports | [consolidatedExports.contract.md](./contracts/consolidatedExports.contract.md) |
69
+ | Pre-push dev log | [prePushDevLog.contract.md](./contracts/prePushDevLog.contract.md) |
70
+ | API registry | [apiDocumentationRegistry.contract.md](./contracts/apiDocumentationRegistry.contract.md) |
71
+ | Case filing storage | `backend/src/modules/case-filing-ai/contracts/storageLayout.contract.js` |
72
+ | Parsed artifacts | `parsedDocumentArtifacts.contract.js` |
73
+ | Pipeline versions | `pipelineVersions.js` |
74
+ | Rule authority | `court-rules/contracts/ruleAuthority.contract.js` |
32
75
 
33
- When you add features with `npm run new:module`, colocate runtime data under `data/<module>/` and optional `evals/golden/` per [EVAL_AND_CI.md](./EVAL_AND_CI.md).
76
+ Human storage doc: [docs/case-filing-ai/STORAGE.md](../case-filing-ai/STORAGE.md)
@@ -7,25 +7,28 @@
7
7
 
8
8
  Regenerable **repo snapshots** for human handoff and agent onboarding — not runtime filing data.
9
9
 
10
- ## Primary paths (handoff)
10
+ ## Primary paths (audit trail)
11
+
12
+ Each condense run writes a **dated, timestamped folder** (same stamp convention as imports):
11
13
 
12
14
  ```text
13
- file-exchange/exports/
15
+ file-exchange/exports/{2026-05-23_15-59-43Z}_consolidated/
14
16
  consolidated-models.json
15
17
  consolidated-prompts.json
16
18
  consolidated-file-structure.json
19
+ manifest.json ← artifact index for the run
17
20
  ```
18
21
 
19
- ## Mirror paths (API / git)
22
+ `npm run condense:all` uses one shared stamp for all three files in a single folder.
23
+
24
+ ## Latest pointers (agents / API)
20
25
 
21
26
  ```text
22
- models/
23
- consolidated-models.json model-condenser API writes here first
24
- consolidated-prompts.json
25
- consolidated-file-structure.json
27
+ file-exchange/exports/consolidated-*.json ← overwritten each run (latest)
28
+ models/consolidated-*.json ← API mirror (latest)
26
29
  ```
27
30
 
28
- Every condense run writes **both** export and mirror.
31
+ Every condense run writes **dated folder + latest copies**.
29
32
 
30
33
  ## Commands
31
34
 
@@ -42,11 +45,12 @@ npm --prefix backend run condense-models # or POST /api/model-condenser/conden
42
45
  |------|--------|
43
46
  | `consolidated-models.json` | Model condenser — schema inventory |
44
47
  | `consolidated-prompts.json` | All `.prompt.md` / `.prompt.js` + manifests |
45
- | `consolidated-file-structure.json` | Full file tree (tree ignore rules) |
48
+ | `consolidated-file-structure.json` | ASCII `treeText` only + `stats` (not nested JSON / flat path lists) |
46
49
 
47
50
  ## File tree ignore (consolidated-file-structure)
48
51
 
49
- Same as pre-push dev log: `node_modules`, `.git`, `dist`, `build`.
52
+ Directory names: `node_modules`, `.git`, `dist`, `build`.
53
+ Skipped subtrees: `data/case-filing-ai/batches`, `eval-bundles`, `case-exports`.
50
54
 
51
55
  ## Deprecated
52
56
 
@@ -35,5 +35,22 @@
35
35
  "registry": "docs/API.md",
36
36
  "lintScript": "scripts/check-api-docs.mjs",
37
37
  "architectureDoc": "docs/architecture/API_DOCUMENTATION_CONTRACT.md"
38
+ },
39
+ "caseFilingStorageLayout": {
40
+ "version": "v001",
41
+ "file": "backend/src/modules/case-filing-ai/contracts/storageLayout.contract.js"
42
+ },
43
+ "parsedDocumentArtifacts": {
44
+ "version": "v001",
45
+ "file": "backend/src/modules/case-filing-ai/contracts/parsedDocumentArtifacts.contract.js"
46
+ },
47
+ "pipelineVersions": {
48
+ "version": "v001",
49
+ "file": "backend/src/modules/case-filing-ai/contracts/pipelineVersions.js",
50
+ "promptVersions": "backend/src/modules/case-filing-ai/prompts/promptVersions.js"
51
+ },
52
+ "ruleAuthority": {
53
+ "version": "v001",
54
+ "file": "backend/src/modules/court-rules/contracts/ruleAuthority.contract.js"
38
55
  }
39
56
  }
@@ -6,35 +6,40 @@ Dated folders for human ↔ agent file handoff. **No sensitive filing text in gi
6
6
 
7
7
  ```text
8
8
  file-exchange/
9
- imports/{2026-05-23_15-59-43Z}/ ← inbound bundles
10
- exports/{2026-05-23_15-59-43Z_...}/ ← session deliverables (batch runs, curl logs)
11
- exports/consolidated-models.json ← repo snapshots (regenerate with condense:all)
12
- exports/consolidated-prompts.json
13
- exports/consolidated-file-structure.json
9
+ imports/{2026-05-23_15-59-43Z}/ ← inbound bundles
10
+ exports/{2026-05-23_15-59-43Z_live-batch-run}/ ← session deliverables
11
+ exports/{2026-05-23_15-59-43Z}_consolidated/ ← repo snapshots (audit trail)
12
+ consolidated-models.json
13
+ consolidated-prompts.json
14
+ consolidated-file-structure.json
15
+ manifest.json
16
+ exports/consolidated-*.json ← latest copies (regenerate with condense:all)
14
17
  ```
15
18
 
16
19
  **Stamp format:** `YYYY-MM-DD_HH-MM-SSZ` via `formatExchangeTimestamp()` in `backend/src/shared/utils/formatExchangeTimestamp.js`.
17
20
 
18
- ## Consolidated exports (in `exports/`)
21
+ ## Consolidated exports
19
22
 
20
23
  ```bash
21
24
  npm run condense:all
22
25
  ```
23
26
 
24
- | File in `exports/` | Mirror (API) |
25
- |--------------------|--------------|
26
- | `consolidated-models.json` | `models/consolidated-models.json` |
27
- | `consolidated-prompts.json` | `models/consolidated-prompts.json` |
28
- | `consolidated-file-structure.json` | `models/consolidated-file-structure.json` |
27
+ Writes all three artifacts into **one dated folder** `{stamp}_consolidated/` and refreshes latest copies:
29
28
 
30
- **Open `file-exchange/exports/`** all three consolidated files sit next to dated batch export folders.
29
+ | Audit (dated folder) | Latest (`exports/` + `models/`) |
30
+ |----------------------|----------------------------------|
31
+ | `{stamp}_consolidated/consolidated-models.json` | `exports/consolidated-models.json`, `models/consolidated-models.json` |
32
+ | `{stamp}_consolidated/consolidated-prompts.json` | same pattern |
33
+ | `{stamp}_consolidated/consolidated-file-structure.json` | same pattern |
34
+
35
+ Individual runs (`npm run condense-prompts`, etc.) create their own `{stamp}_consolidated/` folder for that artifact (plus `manifest.json`).
31
36
 
32
37
  ## Workflow
33
38
 
34
39
  1. Triage loose files into `imports/{stamp}/` (`npm run import:file-exchange -- <path>`).
35
- 2. Process via your domain module APIs using files **under that stamp** only.
36
- 3. Copy batch bundles / reports to `exports/{stamp}/` when done.
37
- 4. Refresh consolidated snapshots: `npm run condense:all`.
40
+ 2. Process via case-filing APIs using files **under that stamp** only.
41
+ 3. Copy batch bundles / reports to `exports/{stamp}_{label}/` when done.
42
+ 4. Refresh consolidated snapshots: `npm run condense:all` → new `exports/{stamp}_consolidated/`.
38
43
 
39
44
  **Cursor agents:** mandatory — see [AGENTS.md](../AGENTS.md) and `.cursor/rules/file-exchange-inbox.mdc`.
40
45
 
@@ -7,7 +7,7 @@
7
7
  "dev": "vite",
8
8
  "build": "vite build",
9
9
  "preview": "vite preview",
10
- "test": "node --test 'src/modules/**/tests/**/*.test.js'"
10
+ "test": "node --test"
11
11
  },
12
12
  "dependencies": {
13
13
  "react": "^18.3.1",
@@ -3,6 +3,8 @@
3
3
  "private": true,
4
4
  "version": "2.0.0",
5
5
  "scripts": {
6
+ "sync:cli-template": "node scripts/sync-cli-template.mjs",
7
+ "export:architecture-starter": "node scripts/export-architecture-starter.mjs",
6
8
  "dev:backend": "npm --prefix backend run dev",
7
9
  "dev:frontend": "npm --prefix frontend run dev",
8
10
  "lint:boundaries": "npm --prefix backend run lint:boundaries",
@@ -12,12 +14,10 @@
12
14
  "lint:repo-artifacts": "node scripts/lint-repo-artifacts.mjs",
13
15
  "lint:architecture": "npm --prefix backend run lint:architecture",
14
16
  "test": "npm --prefix backend test && npm --prefix frontend test",
15
- "test:evals": "npm --prefix backend run test:evals",
16
- "test:ci": "npm run lint:contracts && npm run lint:repo-artifacts && npm run lint:architecture && npm test && npm run test:evals",
17
17
  "new:module": "node scripts/new-module.mjs",
18
18
  "condense-prompts": "node scripts/condense-prompts.mjs",
19
19
  "condense-file-structure": "node scripts/condense-file-structure.mjs",
20
- "condense:all": "npm run condense-prompts && npm run condense-file-structure && npm --prefix backend run condense-models -- --local",
20
+ "condense:all": "node scripts/condense-all.mjs",
21
21
  "dev-log:pre-push": "node scripts/write-pre-push-dev-log.mjs",
22
22
  "dev-log:verify": "node scripts/verify-dev-log.mjs",
23
23
  "import:file-exchange": "node scripts/import-to-file-exchange.mjs"