@pukujan/create-modular-monolith 2.2.0 → 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.
- package/LICENSE +50 -0
- package/README.md +145 -62
- package/package.json +3 -2
- package/template/.cursor/rules/file-exchange-inbox.mdc +1 -1
- package/template/ARCHITECTURE_EXPORT_README.md +30 -0
- package/template/EXPORT_MANIFEST.json +74 -0
- package/template/LICENSE +11 -0
- package/template/NOTICE +12 -0
- package/template/README.md +36 -25
- package/template/backend/package.json +1 -1
- package/template/backend/src/modules/model-condenser/services/modelCondenser.service.js +36 -465
- package/template/backend/src/modules/model-condenser/tests/unit/modelCondenser.service.test.js +2 -3
- package/template/backend/src/shared/utils/consolidatedExport.js +155 -11
- package/template/backend/src/shared/utils/consolidatedExport.test.js +50 -0
- package/template/docs/README.md +0 -1
- package/template/docs/architecture/EVAL_AND_CI.md +68 -41
- package/template/docs/architecture/REPO_ARTIFACT_LAYOUT.md +57 -14
- package/template/docs/architecture/contracts/consolidatedExports.contract.md +14 -10
- package/template/docs/architecture/contracts/manifest.json +17 -0
- package/template/file-exchange/README.md +20 -15
- package/template/frontend/package.json +1 -1
- package/template/package.json +3 -3
- package/template/scripts/condense-all.mjs +52 -0
- package/template/scripts/condense-file-structure.mjs +19 -10
- package/template/scripts/condense-models.mjs +5 -3
- package/template/scripts/condense-prompts.mjs +13 -51
- package/template/scripts/consolidated-output.mjs +22 -10
- package/template/scripts/export-architecture-starter.mjs +389 -0
- package/template/scripts/lib/api-inventory.mjs +16 -61
- package/template/scripts/lib/repo-tree.mjs +26 -4
- package/template/scripts/sync-cli-template.mjs +44 -0
- package/template/scripts/write-pre-push-dev-log.mjs +1 -0
- 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
|
-
/**
|
|
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
|
|
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
|
-
* @
|
|
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
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
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
|
+
});
|
package/template/docs/README.md
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
15
|
-
| `npm run lint:architecture` | Module boundary
|
|
16
|
-
| `npm test` | Unit/integration failures |
|
|
17
|
-
| `npm run test:evals` |
|
|
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`).
|
|
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** =
|
|
27
|
+
**Eval** = compare actual AI output to **expected** (golden) JSON.
|
|
26
28
|
|
|
27
|
-
**Regression** = re-run
|
|
29
|
+
**Regression** = re-run that comparison after you change prompts or code, to see if quality got worse.
|
|
28
30
|
|
|
29
|
-
|
|
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
|
-
|
|
41
|
+
This repo uses **golden files** under `evals/golden/case_001/`:
|
|
32
42
|
|
|
33
|
-
|
|
|
34
|
-
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
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
|
-
|
|
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
|
-
|
|
52
|
+
```bash
|
|
53
|
+
npm run import:file-exchange -- <bundle>
|
|
54
|
+
npm run ingest:golden-expected
|
|
55
|
+
```
|
|
43
56
|
|
|
44
57
|
---
|
|
45
58
|
|
|
46
|
-
##
|
|
47
|
-
|
|
48
|
-
Use `backend/src/shared/utils/traceId.js` in long-running workflows:
|
|
59
|
+
## Running evals locally
|
|
49
60
|
|
|
50
|
-
```
|
|
51
|
-
|
|
61
|
+
```bash
|
|
62
|
+
# All module eval runners (offline for case-filing-ai)
|
|
63
|
+
npm run test:evals
|
|
52
64
|
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
# Case Filing AI only
|
|
66
|
+
npm run test:evals -- case-filing-ai
|
|
55
67
|
```
|
|
56
68
|
|
|
57
|
-
|
|
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
|
-
##
|
|
75
|
+
## Trace IDs (observability)
|
|
62
76
|
|
|
63
|
-
|
|
77
|
+
Each batch gets `batchTraceId`; each document gets `traceId` in:
|
|
64
78
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
-
##
|
|
86
|
+
## Schema validation
|
|
72
87
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
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
|
-
|
|
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
|
|
3
|
+
Canonical paths for runtime data, golden fixtures, and human↔agent exchange.
|
|
4
4
|
|
|
5
5
|
## Roots
|
|
6
6
|
|
|
7
|
-
| Root | Writable at runtime |
|
|
8
|
-
|
|
9
|
-
| `
|
|
10
|
-
| `
|
|
11
|
-
| `
|
|
12
|
-
| `
|
|
13
|
-
| `
|
|
14
|
-
| `
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
-
|
|
23
|
-
|
|
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 **
|
|
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` |
|
|
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
|
-
|
|
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}/
|
|
10
|
-
exports/{2026-05-23_15-59-
|
|
11
|
-
exports/
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
21
|
+
## Consolidated exports
|
|
19
22
|
|
|
20
23
|
```bash
|
|
21
24
|
npm run condense:all
|
|
22
25
|
```
|
|
23
26
|
|
|
24
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
package/template/package.json
CHANGED
|
@@ -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": "
|
|
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"
|