@uwmd/core 1.7.0 → 1.9.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.
- package/dist/agents/bancroft.js +4 -1
- package/dist/agents/bancroft.js.map +1 -1
- package/dist/asset-class.d.ts +98 -0
- package/dist/asset-class.d.ts.map +1 -0
- package/dist/asset-class.js +226 -0
- package/dist/asset-class.js.map +1 -0
- package/dist/browser.d.ts +26 -8
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +25 -5
- package/dist/browser.js.map +1 -1
- package/dist/calc/errors.d.ts +1 -1
- package/dist/calc/errors.d.ts.map +1 -1
- package/dist/calc/errors.js.map +1 -1
- package/dist/calc/evaluator.js +25 -1
- package/dist/calc/evaluator.js.map +1 -1
- package/dist/calc/prng.d.ts +59 -0
- package/dist/calc/prng.d.ts.map +1 -0
- package/dist/calc/prng.js +181 -0
- package/dist/calc/prng.js.map +1 -0
- package/dist/calc/sensitivity.d.ts +76 -0
- package/dist/calc/sensitivity.d.ts.map +1 -0
- package/dist/calc/sensitivity.js +160 -0
- package/dist/calc/sensitivity.js.map +1 -0
- package/dist/calc/stochastic.d.ts +97 -0
- package/dist/calc/stochastic.d.ts.map +1 -0
- package/dist/calc/stochastic.js +265 -0
- package/dist/calc/stochastic.js.map +1 -0
- package/dist/cascade.d.ts.map +1 -1
- package/dist/cascade.js +8 -4
- package/dist/cascade.js.map +1 -1
- package/dist/cli-args.d.ts +37 -0
- package/dist/cli-args.d.ts.map +1 -0
- package/dist/cli-args.js +93 -0
- package/dist/cli-args.js.map +1 -0
- package/dist/cli.js +155 -75
- package/dist/cli.js.map +1 -1
- package/dist/editor.d.ts +18 -1
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +68 -7
- package/dist/editor.js.map +1 -1
- package/dist/format-rules.d.ts +46 -0
- package/dist/format-rules.d.ts.map +1 -0
- package/dist/format-rules.js +134 -0
- package/dist/format-rules.js.map +1 -0
- package/dist/format.d.ts +4 -0
- package/dist/format.d.ts.map +1 -1
- package/dist/format.js +34 -4
- package/dist/format.js.map +1 -1
- package/dist/index.d.ts +27 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -5
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts.map +1 -1
- package/dist/init.js +16 -4
- package/dist/init.js.map +1 -1
- package/dist/integrity-canonical.d.ts.map +1 -1
- package/dist/integrity-canonical.js +10 -2
- package/dist/integrity-canonical.js.map +1 -1
- package/dist/integrity.d.ts +92 -4
- package/dist/integrity.d.ts.map +1 -1
- package/dist/integrity.js +195 -9
- package/dist/integrity.js.map +1 -1
- package/dist/lease-up.d.ts +134 -0
- package/dist/lease-up.d.ts.map +1 -0
- package/dist/lease-up.js +196 -0
- package/dist/lease-up.js.map +1 -0
- package/dist/migrate-source-tags.d.ts +34 -0
- package/dist/migrate-source-tags.d.ts.map +1 -0
- package/dist/migrate-source-tags.js +179 -0
- package/dist/migrate-source-tags.js.map +1 -0
- package/dist/module-runtime.d.ts +57 -0
- package/dist/module-runtime.d.ts.map +1 -0
- package/dist/module-runtime.js +167 -0
- package/dist/module-runtime.js.map +1 -0
- package/dist/module-signing.d.ts +85 -0
- package/dist/module-signing.d.ts.map +1 -0
- package/dist/module-signing.js +136 -0
- package/dist/module-signing.js.map +1 -0
- package/dist/modules.d.ts +42 -0
- package/dist/modules.d.ts.map +1 -1
- package/dist/modules.js +124 -1
- package/dist/modules.js.map +1 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/parser.js +28 -1
- package/dist/parser.js.map +1 -1
- package/dist/protocol.d.ts +249 -24
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +387 -33
- package/dist/protocol.js.map +1 -1
- package/dist/renderer.d.ts +10 -0
- package/dist/renderer.d.ts.map +1 -1
- package/dist/renderer.js +72 -8
- package/dist/renderer.js.map +1 -1
- package/dist/runner.d.ts.map +1 -1
- package/dist/runner.js +9 -3
- package/dist/runner.js.map +1 -1
- package/dist/types.d.ts +124 -5
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +44 -0
- package/dist/types.js.map +1 -1
- package/dist/validator.d.ts +26 -2
- package/dist/validator.d.ts.map +1 -1
- package/dist/validator.js +336 -19
- package/dist/validator.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -2
package/dist/lease-up.js
ADDED
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// Lease-up schedule — state-and-verify trajectory (RFC 0008, UW_FORMAT_SPEC §4.25).
|
|
2
|
+
//
|
|
3
|
+
// A deal states the period-by-period path from current to stabilized rents —
|
|
4
|
+
// natural turnover on a value-add, or an absorption curve on ground-up — plus
|
|
5
|
+
// the assumption set that drives it and a stabilized summary. This module
|
|
6
|
+
// recomputes each stated aggregate over a FIXED, CLOSED vocabulary and reports
|
|
7
|
+
// a three-state verdict, the same shape as `verifyCapitalStack` and
|
|
8
|
+
// `verifyRollup` (RFC 0026 pattern).
|
|
9
|
+
//
|
|
10
|
+
// This deliberately does NOT touch the Tier-3 calc engine. The schedule is
|
|
11
|
+
// stated data, not formulas: a variable-length period array is not addressable
|
|
12
|
+
// by a pack formula (no iteration, RFC 0019 §1), but a deterministic TypeScript
|
|
13
|
+
// verifier walks it directly. Structural rules (period grammar, monotonicity,
|
|
14
|
+
// empty schedules) are validator errors (`LU-01`…`LU-04`, validator.ts), not
|
|
15
|
+
// verifier findings — structure is validation, arithmetic is verification.
|
|
16
|
+
// Browser-safe; performs no I/O.
|
|
17
|
+
import { getSection, deepGet } from './parser.js';
|
|
18
|
+
import { resolveDealSize } from './protocol.js';
|
|
19
|
+
// ─── Quantization ────────────────────────────────────────────────────────────
|
|
20
|
+
/**
|
|
21
|
+
* The decimal quantum each figure family is compared at (protocol §VIII.5
|
|
22
|
+
* posture: both sides quantize at the same boundary). Currency to cents; rates
|
|
23
|
+
* to 4 places, like the capital-stack sizing table. Exported so an emitting
|
|
24
|
+
* surface quantizes where this verifier does rather than keeping its own copy.
|
|
25
|
+
*/
|
|
26
|
+
export const LEASE_UP_VERIFY_DECIMALS = Object.freeze({
|
|
27
|
+
currency: 2,
|
|
28
|
+
rate: 4,
|
|
29
|
+
sf: 2,
|
|
30
|
+
});
|
|
31
|
+
/**
|
|
32
|
+
* The relative tolerance CC-15 allows between the schedule's final period /
|
|
33
|
+
* stabilized summary and `noi_model`'s stabilized figures (2%). Deliberate,
|
|
34
|
+
* not softness: unlike CC-01 (one number restated in two places, exact), the
|
|
35
|
+
* trajectory endpoint and the stabilized-year projection are two different
|
|
36
|
+
* models of stabilization, and demanding exact agreement would force
|
|
37
|
+
* producers to hand-tune one to echo the other — destroying the
|
|
38
|
+
* independent-model signal the check exists to read (RFC 0008).
|
|
39
|
+
*/
|
|
40
|
+
export const LEASE_UP_STABILIZED_TOLERANCE = 0.02;
|
|
41
|
+
function roundTo(value, decimals) {
|
|
42
|
+
const f = 10 ** decimals;
|
|
43
|
+
return Math.round(value * f) / f;
|
|
44
|
+
}
|
|
45
|
+
function isNum(v) {
|
|
46
|
+
return typeof v === 'number' && Number.isFinite(v);
|
|
47
|
+
}
|
|
48
|
+
// ─── Verification ────────────────────────────────────────────────────────────
|
|
49
|
+
/**
|
|
50
|
+
* Recompute every stated aggregate and report a three-state verdict:
|
|
51
|
+
* - a figure disagrees beyond its quantum → `failed`
|
|
52
|
+
* - a figure reads an input the document does not supply → `unverifiable`
|
|
53
|
+
* - otherwise → `verified`
|
|
54
|
+
*
|
|
55
|
+
* The closed recompute vocabulary (§4.25):
|
|
56
|
+
* - per period: `net_cash_flow` = `rent_revenue + concessions + ti_lc_capex`
|
|
57
|
+
* (all stated; a missing component is `unverifiable` for that row)
|
|
58
|
+
* - `stabilized_summary.occupied_sf` against the final period's
|
|
59
|
+
* - `stabilized_summary.occupancy_rate` = final `occupied_sf` ÷ `ctx.total_sf`
|
|
60
|
+
*
|
|
61
|
+
* A `verified` schedule means the stated figures follow deterministically from
|
|
62
|
+
* the stated rows. It does not mean the trajectory is achievable.
|
|
63
|
+
*/
|
|
64
|
+
export function verifyLeaseUpSchedule(schedule, ctx) {
|
|
65
|
+
const issues = [];
|
|
66
|
+
const rows = schedule.schedule ?? [];
|
|
67
|
+
for (const row of rows) {
|
|
68
|
+
if (!isNum(row.net_cash_flow))
|
|
69
|
+
continue; // nothing stated, nothing to verify
|
|
70
|
+
if (!isNum(row.rent_revenue) || !isNum(row.concessions) || !isNum(row.ti_lc_capex)) {
|
|
71
|
+
issues.push({
|
|
72
|
+
code: 'LU-UNEVALUABLE',
|
|
73
|
+
severity: 'indeterminate',
|
|
74
|
+
period: row.period,
|
|
75
|
+
message: `Period ${row.period} states net_cash_flow but omits a component (rent_revenue, concessions, ti_lc_capex), so it cannot be verified.`,
|
|
76
|
+
});
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const dp = LEASE_UP_VERIFY_DECIMALS.currency;
|
|
80
|
+
const recomputed = roundTo(row.rent_revenue + row.concessions + row.ti_lc_capex, dp);
|
|
81
|
+
const stated = roundTo(row.net_cash_flow, dp);
|
|
82
|
+
if (stated !== recomputed) {
|
|
83
|
+
issues.push({
|
|
84
|
+
code: 'LU-NCF-DISAGREES',
|
|
85
|
+
severity: 'failure',
|
|
86
|
+
period: row.period,
|
|
87
|
+
message: `Period ${row.period} states net_cash_flow ${row.net_cash_flow} but the components sum to ${recomputed}.`,
|
|
88
|
+
expected: String(stated),
|
|
89
|
+
actual: String(recomputed),
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const summary = schedule.stabilized_summary;
|
|
94
|
+
const final = rows.length > 0 ? rows[rows.length - 1] : undefined;
|
|
95
|
+
if (summary && final) {
|
|
96
|
+
if (isNum(summary.occupied_sf)) {
|
|
97
|
+
if (!isNum(final.occupied_sf)) {
|
|
98
|
+
issues.push({
|
|
99
|
+
code: 'LU-UNEVALUABLE',
|
|
100
|
+
severity: 'indeterminate',
|
|
101
|
+
message: `stabilized_summary states occupied_sf but the final period (${final.period}) does not, so it cannot be verified.`,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const dp = LEASE_UP_VERIFY_DECIMALS.sf;
|
|
106
|
+
const stated = roundTo(summary.occupied_sf, dp);
|
|
107
|
+
const recomputed = roundTo(final.occupied_sf, dp);
|
|
108
|
+
if (stated !== recomputed) {
|
|
109
|
+
issues.push({
|
|
110
|
+
code: 'LU-SUMMARY-DISAGREES',
|
|
111
|
+
severity: 'failure',
|
|
112
|
+
message: `stabilized_summary.occupied_sf states ${summary.occupied_sf} but the final period (${final.period}) states ${final.occupied_sf}.`,
|
|
113
|
+
expected: String(stated),
|
|
114
|
+
actual: String(recomputed),
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
if (isNum(summary.occupancy_rate)) {
|
|
120
|
+
const sf = isNum(final.occupied_sf) ? final.occupied_sf : summary.occupied_sf;
|
|
121
|
+
if (!isNum(sf) || ctx.total_sf === null || ctx.total_sf === 0) {
|
|
122
|
+
issues.push({
|
|
123
|
+
code: 'LU-UNEVALUABLE',
|
|
124
|
+
severity: 'indeterminate',
|
|
125
|
+
message: 'stabilized_summary states occupancy_rate but no square-foot denominator resolves through the size-intensive registry (Protocol §XIII), so it cannot be verified.',
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
const dp = LEASE_UP_VERIFY_DECIMALS.rate;
|
|
130
|
+
const stated = roundTo(summary.occupancy_rate, dp);
|
|
131
|
+
const recomputed = roundTo(sf / ctx.total_sf, dp);
|
|
132
|
+
if (stated !== recomputed) {
|
|
133
|
+
issues.push({
|
|
134
|
+
code: 'LU-SUMMARY-DISAGREES',
|
|
135
|
+
severity: 'failure',
|
|
136
|
+
message: `stabilized_summary.occupancy_rate states ${summary.occupancy_rate} but ${sf} ÷ ${ctx.total_sf} recomputes to ${recomputed}.`,
|
|
137
|
+
expected: String(stated),
|
|
138
|
+
actual: String(recomputed),
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (issues.some((i) => i.severity === 'failure')) {
|
|
145
|
+
return { verdict: 'failed', issues };
|
|
146
|
+
}
|
|
147
|
+
if (issues.some((i) => i.severity === 'indeterminate')) {
|
|
148
|
+
return { verdict: 'unverifiable', issues };
|
|
149
|
+
}
|
|
150
|
+
return { verdict: 'verified', issues };
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Pull the occupancy denominator from a parsed document through the Protocol
|
|
154
|
+
* §XIII size-intensive registry — which is what the registry exists for. Only
|
|
155
|
+
* a `sqft`-unit primary size is a valid denominator for `occupied_sf`; a
|
|
156
|
+
* keys/units/beds class resolves to `null`, which makes `occupancy_rate`
|
|
157
|
+
* `unverifiable` rather than dimensionally wrong. A multifamily document that
|
|
158
|
+
* states its secondary `total_nra_sqft` supplies the denominator that way.
|
|
159
|
+
*/
|
|
160
|
+
export function leaseUpContext(parsed) {
|
|
161
|
+
const size = resolveDealSize(parsed);
|
|
162
|
+
if (size && size.unit === 'sqft')
|
|
163
|
+
return { total_sf: size.quantity };
|
|
164
|
+
// Secondary sqft fields (Protocol §XIII secondary lists) still denominate.
|
|
165
|
+
const property = getSection(parsed, 'property');
|
|
166
|
+
if (property) {
|
|
167
|
+
for (const path of ['total_nra_sqft', 'rentable_square_feet', 'net_rentable_square_feet']) {
|
|
168
|
+
const v = deepGet(property.content, path);
|
|
169
|
+
if (isNum(v) && v > 0)
|
|
170
|
+
return { total_sf: v };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return { total_sf: null };
|
|
174
|
+
}
|
|
175
|
+
// ─── Period grammar (shared with the validator) ──────────────────────────────
|
|
176
|
+
const QUARTER_RE = /^(\d{4})-Q([1-4])$/;
|
|
177
|
+
const MONTH_RE = /^(\d{4})-(0[1-9]|1[0-2])$/;
|
|
178
|
+
/**
|
|
179
|
+
* A period's ordinal on its granularity's axis, or `null` when the string is
|
|
180
|
+
* outside the grammar for that granularity. Consecutive periods differ by
|
|
181
|
+
* exactly 1, which is what makes the validator's gap-free check (`LU-02`) a
|
|
182
|
+
* subtraction rather than a calendar library.
|
|
183
|
+
*/
|
|
184
|
+
export function leaseUpPeriodOrdinal(period, granularity) {
|
|
185
|
+
if (granularity === 'quarterly') {
|
|
186
|
+
const m = QUARTER_RE.exec(period);
|
|
187
|
+
if (!m)
|
|
188
|
+
return null;
|
|
189
|
+
return Number(m[1]) * 4 + (Number(m[2]) - 1);
|
|
190
|
+
}
|
|
191
|
+
const m = MONTH_RE.exec(period);
|
|
192
|
+
if (!m)
|
|
193
|
+
return null;
|
|
194
|
+
return Number(m[1]) * 12 + (Number(m[2]) - 1);
|
|
195
|
+
}
|
|
196
|
+
//# sourceMappingURL=lease-up.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lease-up.js","sourceRoot":"","sources":["../src/lease-up.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Result of migrating one document. */
|
|
2
|
+
export interface SourceTagMigration {
|
|
3
|
+
content: string;
|
|
4
|
+
/** Number of blocks whose `_meta` changed. */
|
|
5
|
+
changed: number;
|
|
6
|
+
/** Sources the mapping did not recognize, left in place. */
|
|
7
|
+
unmapped: string[];
|
|
8
|
+
}
|
|
9
|
+
interface ActorAndResolution {
|
|
10
|
+
source: string;
|
|
11
|
+
resolution?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Map one legacy `_meta.source` value. Returns null when the value is already
|
|
15
|
+
* well-formed (actor grammar) or unknown to the mapping.
|
|
16
|
+
*
|
|
17
|
+
* `agentId` — the block's `_meta.agent_id`, consulted for method-only tags
|
|
18
|
+
* that an agent stamped (`ai_extracted`, `agent_computed`), so the actor is
|
|
19
|
+
* recovered from the block instead of invented.
|
|
20
|
+
*/
|
|
21
|
+
export declare function mapLegacySource(source: string, agentId?: string | null): ActorAndResolution | null;
|
|
22
|
+
/**
|
|
23
|
+
* Migrate every section block of a structured `.uwx.md` / legacy `.uw.md`
|
|
24
|
+
* document. Bytes outside migrated blocks are preserved exactly; a migrated
|
|
25
|
+
* block is re-serialized with 2-space indentation (the corpus convention) and
|
|
26
|
+
* its fence `source=` mirror updated to the new actor.
|
|
27
|
+
*
|
|
28
|
+
* Blocks carrying `content_hash` are refused (reported via `unmapped` as
|
|
29
|
+
* `<source> [content_hash]`) rather than silently invalidating an integrity
|
|
30
|
+
* chain — re-stamping a hashed chain is a deliberate act, not a codemod.
|
|
31
|
+
*/
|
|
32
|
+
export declare function migrateSourceTags(content: string): SourceTagMigration;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=migrate-source-tags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-source-tags.d.ts","sourceRoot":"","sources":["../src/migrate-source-tags.ts"],"names":[],"mappings":"AAkBA,wCAAwC;AACxC,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,8CAA8C;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,UAAU,kBAAkB;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAQD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,GACtB,kBAAkB,GAAG,IAAI,CAiD3B;AAKD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,kBAAkB,CA8FrE"}
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
// RFC 0031 — `uwmd migrate --source-tags`: rewrite legacy `_meta.source`
|
|
2
|
+
// values into the actor / resolution split.
|
|
3
|
+
//
|
|
4
|
+
// The mapping is total over every source the corpus measurement surfaced
|
|
5
|
+
// (RFC 0031 §"Measured against our own corpus") and mechanical: a canonical
|
|
6
|
+
// SOURCE_TAGS value moves to `_meta.resolution` and the actor field is filled
|
|
7
|
+
// from what the block itself records (agent_id where present, `manual` for
|
|
8
|
+
// user-entered methods, `system/uwmd` for engine-resolved ones); retired
|
|
9
|
+
// colon forms swap delimiter into their namespace; bare words map per the
|
|
10
|
+
// table below. A source the mapping does not know is left untouched and
|
|
11
|
+
// reported, never guessed at.
|
|
12
|
+
import { SOURCE_TAGS } from './types.js';
|
|
13
|
+
import { parseActorSource } from './protocol.js';
|
|
14
|
+
const CANONICAL = new Set(SOURCE_TAGS);
|
|
15
|
+
/** Sanitize an id into the actor grammar's id charset. */
|
|
16
|
+
function sanitizeId(raw) {
|
|
17
|
+
const cleaned = raw.replace(/[^A-Za-z0-9._-]+/g, '-').replace(/^[^A-Za-z0-9]+/, '');
|
|
18
|
+
return cleaned.length > 0 ? cleaned : 'unspecified';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Map one legacy `_meta.source` value. Returns null when the value is already
|
|
22
|
+
* well-formed (actor grammar) or unknown to the mapping.
|
|
23
|
+
*
|
|
24
|
+
* `agentId` — the block's `_meta.agent_id`, consulted for method-only tags
|
|
25
|
+
* that an agent stamped (`ai_extracted`, `agent_computed`), so the actor is
|
|
26
|
+
* recovered from the block instead of invented.
|
|
27
|
+
*/
|
|
28
|
+
export function mapLegacySource(source, agentId) {
|
|
29
|
+
if (parseActorSource(source).kind !== 'invalid')
|
|
30
|
+
return null; // already well-formed
|
|
31
|
+
// Canonical resolution tags in the actor field: the tag becomes
|
|
32
|
+
// `resolution`; the actor is recovered from what the tag itself implies.
|
|
33
|
+
if (CANONICAL.has(source)) {
|
|
34
|
+
const resolution = source;
|
|
35
|
+
if (source === 'user_input' || source === 'user_override') {
|
|
36
|
+
return { source: 'manual', resolution };
|
|
37
|
+
}
|
|
38
|
+
if (source === 'ai_extracted' || source === 'agent_computed') {
|
|
39
|
+
return { source: agentId ? `agent/${sanitizeId(agentId)}` : 'agent/unattributed', resolution };
|
|
40
|
+
}
|
|
41
|
+
// Engine-resolved methods: the reference resolver wrote the block.
|
|
42
|
+
return { source: 'system/uwmd', resolution };
|
|
43
|
+
}
|
|
44
|
+
// Retired colon forms — delimiter swap into the owning namespace.
|
|
45
|
+
const colon = /^(agent|wizard|engine|import|market|profile|scenario|user):(.*)$/.exec(source);
|
|
46
|
+
if (colon) {
|
|
47
|
+
const id = sanitizeId(colon[2] ?? '');
|
|
48
|
+
switch (colon[1]) {
|
|
49
|
+
case 'agent': return { source: `agent/${id}` };
|
|
50
|
+
case 'engine': return { source: `system/${id}` };
|
|
51
|
+
case 'import': return { source: `document/${id}` };
|
|
52
|
+
case 'market': return { source: `system/${id}`, resolution: 'market_data' };
|
|
53
|
+
case 'profile': return { source: 'system/investor-profile', resolution: 'investor_profile' };
|
|
54
|
+
case 'scenario': return { source: 'system/scenarios', resolution: 'scenario_default' };
|
|
55
|
+
case 'wizard': return { source: 'manual', resolution: 'user_input' };
|
|
56
|
+
case 'user':
|
|
57
|
+
return colon[2] === 'override'
|
|
58
|
+
? { source: 'manual', resolution: 'user_override' }
|
|
59
|
+
: { source: 'manual', resolution: 'user_input' };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Bare words the corpus measurement surfaced.
|
|
63
|
+
switch (source) {
|
|
64
|
+
case 'user': return { source: 'manual' };
|
|
65
|
+
case 'wizard': return { source: 'manual', resolution: 'user_input' };
|
|
66
|
+
case 'extractor': return { source: 'system/extractor', resolution: 'ai_extracted' };
|
|
67
|
+
case 'engine': return { source: 'system/engine' };
|
|
68
|
+
case 'system': return { source: 'system/unspecified' };
|
|
69
|
+
}
|
|
70
|
+
// Bancroft layer ids stamped bare (`L6`, `L6-01`).
|
|
71
|
+
if (/^L\d+(-\d+)?[a-b]?$/i.test(source))
|
|
72
|
+
return { source: `agent/${sanitizeId(source)}` };
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const FENCE_OPEN_RE = /^```json\s+uw:section=(\S+)(.*)?$/;
|
|
76
|
+
const FENCE_CLOSE_RE = /^```\s*$/;
|
|
77
|
+
/**
|
|
78
|
+
* Migrate every section block of a structured `.uwx.md` / legacy `.uw.md`
|
|
79
|
+
* document. Bytes outside migrated blocks are preserved exactly; a migrated
|
|
80
|
+
* block is re-serialized with 2-space indentation (the corpus convention) and
|
|
81
|
+
* its fence `source=` mirror updated to the new actor.
|
|
82
|
+
*
|
|
83
|
+
* Blocks carrying `content_hash` are refused (reported via `unmapped` as
|
|
84
|
+
* `<source> [content_hash]`) rather than silently invalidating an integrity
|
|
85
|
+
* chain — re-stamping a hashed chain is a deliberate act, not a codemod.
|
|
86
|
+
*/
|
|
87
|
+
export function migrateSourceTags(content) {
|
|
88
|
+
// EOL-aware: a CRLF working copy (Windows autocrlf) would otherwise blind
|
|
89
|
+
// the fence regexes — `.` and `$` refuse to cross a bare `\r` — and the
|
|
90
|
+
// rewrite must give back the endings it was handed.
|
|
91
|
+
const eol = content.includes('\r\n') ? '\r\n' : '\n';
|
|
92
|
+
const lines = content.split(/\r\n|\n/);
|
|
93
|
+
const out = [];
|
|
94
|
+
const unmapped = [];
|
|
95
|
+
let changed = 0;
|
|
96
|
+
let i = 0;
|
|
97
|
+
while (i < lines.length) {
|
|
98
|
+
const line = lines[i];
|
|
99
|
+
const fence = FENCE_OPEN_RE.exec(line);
|
|
100
|
+
if (!fence) {
|
|
101
|
+
out.push(line);
|
|
102
|
+
i++;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
// Collect the block.
|
|
106
|
+
const fenceLine = line;
|
|
107
|
+
const jsonLines = [];
|
|
108
|
+
i++;
|
|
109
|
+
while (i < lines.length && !FENCE_CLOSE_RE.test(lines[i])) {
|
|
110
|
+
jsonLines.push(lines[i]);
|
|
111
|
+
i++;
|
|
112
|
+
}
|
|
113
|
+
const closed = i < lines.length;
|
|
114
|
+
const rawJson = jsonLines.join('\n');
|
|
115
|
+
let parsed = null;
|
|
116
|
+
try {
|
|
117
|
+
parsed = JSON.parse(rawJson);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
parsed = null;
|
|
121
|
+
}
|
|
122
|
+
const meta = parsed?.['_meta'];
|
|
123
|
+
const mapped = meta && typeof meta.source === 'string'
|
|
124
|
+
? mapLegacySource(meta.source, meta.agent_id)
|
|
125
|
+
: null;
|
|
126
|
+
// Field overrides migrate independently of the block-level source.
|
|
127
|
+
const overrides = (meta?.field_overrides ?? []);
|
|
128
|
+
const overrideMoves = overrides.filter((o) => typeof o.source === 'string' && CANONICAL.has(o.source) && o.resolution === undefined);
|
|
129
|
+
if (!parsed || !meta || (!mapped && overrideMoves.length === 0)) {
|
|
130
|
+
if (meta && typeof meta.source === 'string'
|
|
131
|
+
&& parseActorSource(meta.source).kind === 'invalid' && !mapped) {
|
|
132
|
+
unmapped.push(meta.source);
|
|
133
|
+
}
|
|
134
|
+
out.push(fenceLine, ...jsonLines);
|
|
135
|
+
if (closed) {
|
|
136
|
+
out.push(lines[i]);
|
|
137
|
+
i++;
|
|
138
|
+
}
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (typeof meta.content_hash === 'string') {
|
|
142
|
+
unmapped.push(`${String(meta.source)} [content_hash]`);
|
|
143
|
+
out.push(fenceLine, ...jsonLines);
|
|
144
|
+
if (closed) {
|
|
145
|
+
out.push(lines[i]);
|
|
146
|
+
i++;
|
|
147
|
+
}
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (mapped) {
|
|
151
|
+
// Rebuild _meta so `resolution` sits directly after `source`, keeping
|
|
152
|
+
// the provenance pair adjacent in the serialized block.
|
|
153
|
+
const rebuilt = {};
|
|
154
|
+
for (const [k, v] of Object.entries(meta)) {
|
|
155
|
+
if (k === 'resolution')
|
|
156
|
+
continue;
|
|
157
|
+
rebuilt[k] = k === 'source' ? mapped.source : v;
|
|
158
|
+
if (k === 'source') {
|
|
159
|
+
const resolution = mapped.resolution ?? meta['resolution'];
|
|
160
|
+
if (resolution !== undefined)
|
|
161
|
+
rebuilt['resolution'] = resolution;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
parsed['_meta'] = rebuilt;
|
|
165
|
+
}
|
|
166
|
+
for (const o of overrideMoves) {
|
|
167
|
+
o.resolution = o.source;
|
|
168
|
+
delete o.source;
|
|
169
|
+
}
|
|
170
|
+
changed++;
|
|
171
|
+
out.push(mapped ? fenceLine.replace(/\bsource=\S+/, `source=${mapped.source}`) : fenceLine, ...JSON.stringify(parsed, null, 2).split('\n'));
|
|
172
|
+
if (closed) {
|
|
173
|
+
out.push(lines[i]);
|
|
174
|
+
i++;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return { content: out.join(eol), changed, unmapped: [...new Set(unmapped)] };
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=migrate-source-tags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"migrate-source-tags.js","sourceRoot":"","sources":["../src/migrate-source-tags.ts"],"names":[],"mappings":"AAAA,yEAAyE;AACzE,4CAA4C;AAC5C,EAAE;AACF,yEAAyE;AACzE,4EAA4E;AAC5E,8EAA8E;AAC9E,2EAA2E;AAC3E,yEAAyE;AACzE,0EAA0E;AAC1E,wEAAwE;AACxE,8BAA8B;AAG9B,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjD,MAAM,SAAS,GAAwB,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC;AAgB5D,0DAA0D;AAC1D,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAC,mBAAmB,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;IACpF,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,aAAa,CAAC;AACtD,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAc,EACd,OAAuB;IAEvB,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC,CAAC,sBAAsB;IAEpF,gEAAgE;IAChE,yEAAyE;IACzE,IAAI,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,MAAM,UAAU,GAAG,MAAM,CAAC;QAC1B,IAAI,MAAM,KAAK,YAAY,IAAI,MAAM,KAAK,eAAe,EAAE,CAAC;YAC1D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC;QAC1C,CAAC;QACD,IAAI,MAAM,KAAK,cAAc,IAAI,MAAM,KAAK,gBAAgB,EAAE,CAAC;YAC7D,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,oBAAoB,EAAE,UAAU,EAAE,CAAC;QACjG,CAAC;QACD,mEAAmE;QACnE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,CAAC;IAC/C,CAAC;IAED,kEAAkE;IAClE,MAAM,KAAK,GAAG,kEAAkE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC9F,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACtC,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;YACjB,KAAK,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;YAC/C,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC;YACjD,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;YACnD,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,EAAE,UAAU,EAAE,aAAa,EAAE,CAAC;YAC5E,KAAK,SAAS,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,yBAAyB,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;YAC7F,KAAK,UAAU,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,kBAAkB,EAAE,CAAC;YACvF,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;YACrE,KAAK,MAAM;gBACT,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,UAAU;oBAC5B,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,eAAe,EAAE;oBACnD,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;QACvD,CAAC;IACH,CAAC;IAED,8CAA8C;IAC9C,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,MAAM,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;QACzC,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,UAAU,EAAE,YAAY,EAAE,CAAC;QACrE,KAAK,WAAW,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC;QACpF,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,CAAC;QAClD,KAAK,QAAQ,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IACzD,CAAC;IAED,mDAAmD;IACnD,IAAI,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,SAAS,UAAU,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;IAE1F,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,aAAa,GAAG,mCAAmC,CAAC;AAC1D,MAAM,cAAc,GAAG,UAAU,CAAC;AAElC;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe;IAC/C,0EAA0E;IAC1E,wEAAwE;IACxE,oDAAoD;IACpD,MAAM,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;IACrD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACvC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAE,CAAC;QACvB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACf,CAAC,EAAE,CAAC;YACJ,SAAS;QACX,CAAC;QAED,qBAAqB;QACrB,MAAM,SAAS,GAAG,IAAI,CAAC;QACvB,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,CAAC,EAAE,CAAC;QACJ,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;YAC3D,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;YAC1B,CAAC,EAAE,CAAC;QACN,CAAC;QACD,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;QAChC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAErC,IAAI,MAAM,GAAmC,IAAI,CAAC;QAClD,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAA4B,CAAC;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,OAAO,CAAmD,CAAC;QACjF,MAAM,MAAM,GAAG,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;YACpD,CAAC,CAAC,eAAe,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC;YAC7C,CAAC,CAAC,IAAI,CAAC;QAET,mEAAmE;QACnE,MAAM,SAAS,GAAG,CAAC,IAAI,EAAE,eAAe,IAAI,EAAE,CAAkD,CAAC;QACjG,MAAM,aAAa,GAAG,SAAS,CAAC,MAAM,CACpC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,QAAQ,IAAI,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,KAAK,SAAS,CAC7F,CAAC;QAEF,IAAI,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;YAChE,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ;mBACtC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;gBACjE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAC7B,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,SAAS,CAAC,CAAC;YAClC,IAAI,MAAM,EAAE,CAAC;gBAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;gBAAC,CAAC,EAAE,CAAC;YAAC,CAAC;YACzC,SAAS;QACX,CAAC;QAED,IAAI,OAAO,IAAI,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;YAC1C,QAAQ,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC;YACvD,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,SAAS,CAAC,CAAC;YAClC,IAAI,MAAM,EAAE,CAAC;gBAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;gBAAC,CAAC,EAAE,CAAC;YAAC,CAAC;YACzC,SAAS;QACX,CAAC;QAED,IAAI,MAAM,EAAE,CAAC;YACX,sEAAsE;YACtE,wDAAwD;YACxD,MAAM,OAAO,GAA4B,EAAE,CAAC;YAC5C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC1C,IAAI,CAAC,KAAK,YAAY;oBAAE,SAAS;gBACjC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;gBAChD,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;oBACnB,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,IAAK,IAAI,CAAC,YAAY,CAAwB,CAAC;oBACnF,IAAI,UAAU,KAAK,SAAS;wBAAE,OAAO,CAAC,YAAY,CAAC,GAAG,UAAU,CAAC;gBACnE,CAAC;YACH,CAAC;YACD,MAAM,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;QAC5B,CAAC;QACD,KAAK,MAAM,CAAC,IAAI,aAAa,EAAE,CAAC;YAC9B,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;YACxB,OAAO,CAAC,CAAC,MAAM,CAAC;QAClB,CAAC;QAED,OAAO,EAAE,CAAC;QACV,GAAG,CAAC,IAAI,CACN,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,cAAc,EAAE,UAAU,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,EACjF,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAC/C,CAAC;QACF,IAAI,MAAM,EAAE,CAAC;YAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;YAAC,CAAC,EAAE,CAAC;QAAC,CAAC;IAC3C,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,EAAE,CAAC;AAC/E,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { ModuleManifest, CalcResult } from './protocol.js';
|
|
2
|
+
import type { ModuleRegistry } from './modules.js';
|
|
3
|
+
import type { ParsedUWFile, ValidationMessage } from './types.js';
|
|
4
|
+
export interface ModuleRuntimeOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Restrict to modules declaring this asset class (plus modules that declare
|
|
7
|
+
* none, which apply to all). Defaults to the file's own
|
|
8
|
+
* `frontmatter.asset_class`.
|
|
9
|
+
*/
|
|
10
|
+
assetClass?: string;
|
|
11
|
+
}
|
|
12
|
+
/** One module calculation and what it produced. */
|
|
13
|
+
export interface ModuleCalcOutcome {
|
|
14
|
+
module_id: string;
|
|
15
|
+
result: CalcResult;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Evaluate every calculation the applicable modules declare, in declaration
|
|
19
|
+
* order, threading each result into the next as `prior_results`.
|
|
20
|
+
*
|
|
21
|
+
* Order matters and is the manifest's: `revpar_index` divides by `revpar`, so
|
|
22
|
+
* `revpar` must already be in `prior_results` when it runs. Sorting or
|
|
23
|
+
* parallelizing would break that for no gain — and a module author who orders
|
|
24
|
+
* their declarations wrongly gets a `CALC-REF` error naming the missing id,
|
|
25
|
+
* which is a better failure than a silent `null`.
|
|
26
|
+
*/
|
|
27
|
+
export declare function evaluateModuleCalculations(parsed: ParsedUWFile, registry: ModuleRegistry, options?: ModuleRuntimeOptions): ModuleCalcOutcome[];
|
|
28
|
+
/**
|
|
29
|
+
* Run the applicable modules' `validations` and section requirements.
|
|
30
|
+
*
|
|
31
|
+
* A rule is an assertion of what must be TRUE. It fires an issue when it
|
|
32
|
+
* evaluates to `false` — and, deliberately, **not** when it evaluates to
|
|
33
|
+
* `null`. Null is the calc engine's "the inputs are absent", and a document
|
|
34
|
+
* that simply does not carry `hotel_brand` has not violated a rule about
|
|
35
|
+
* franchise fees; it has said nothing about them. Reporting absence as
|
|
36
|
+
* violation would make every module rule fire on every partial file, which is
|
|
37
|
+
* most files most of the time.
|
|
38
|
+
*
|
|
39
|
+
* A rule that fails to *evaluate* — an unknown function, an unusable argument —
|
|
40
|
+
* is reported under `MOD-RULE-ERROR` rather than swallowed, and a module
|
|
41
|
+
* *calculation* that fails is reported under `MOD-CALC-ERROR`. A silently
|
|
42
|
+
* skipped rule is a rule the author believes is protecting them.
|
|
43
|
+
*/
|
|
44
|
+
export declare function validateAgainstModules(parsed: ParsedUWFile, registry: ModuleRegistry, options?: ModuleRuntimeOptions): ValidationMessage[];
|
|
45
|
+
/**
|
|
46
|
+
* Sections a module declares `required: true` must be present.
|
|
47
|
+
*
|
|
48
|
+
* Only presence. Validating a section's contents against its declared JSON
|
|
49
|
+
* Schema would need a JSON Schema validator, and `@uwmd/core` takes no such
|
|
50
|
+
* dependency — see the layering invariant. The schema in the manifest is
|
|
51
|
+
* normative and a host that already has a validator SHOULD apply it; core
|
|
52
|
+
* checks the part it can check honestly rather than shipping a
|
|
53
|
+
* half-implemented subset of JSON Schema that quietly accepts what a real
|
|
54
|
+
* validator would reject.
|
|
55
|
+
*/
|
|
56
|
+
export declare function checkModuleSections(parsed: ParsedUWFile, manifest: ModuleManifest): ValidationMessage[];
|
|
57
|
+
//# sourceMappingURL=module-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module-runtime.d.ts","sourceRoot":"","sources":["../src/module-runtime.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,cAAc,EAAwB,UAAU,EAAE,MAAM,eAAe,CAAC;AACtF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAElE,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,mDAAmD;AACnD,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,UAAU,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,cAAc,EACxB,OAAO,GAAE,oBAAyB,GACjC,iBAAiB,EAAE,CAuBrB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,cAAc,EACxB,OAAO,GAAE,oBAAyB,GACjC,iBAAiB,EAAE,CA+BrB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,YAAY,EACpB,QAAQ,EAAE,cAAc,GACvB,iBAAiB,EAAE,CAerB"}
|