segreant 0.0.0-stage → 0.2.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/LICENSE +116 -0
- package/LICENSING.md +62 -0
- package/README.md +315 -2
- package/baselines/lift-baselines.json +22 -0
- package/bin/publication-lock.mjs +748 -0
- package/bin/runtime-snapshot.mjs +266 -0
- package/bin/segreant-statusline.mjs +20 -0
- package/bin/segreant.mjs +96 -0
- package/dist/alerts/detect.js +245 -0
- package/dist/alerts/notify.js +66 -0
- package/dist/alloc/apply.js +0 -0
- package/dist/alloc/epistemic.js +154 -0
- package/dist/alloc/exact.js +714 -0
- package/dist/alloc/rules.js +0 -0
- package/dist/billing/countermodels.js +123 -0
- package/dist/billing/epistemic.js +636 -0
- package/dist/billing/importer.js +75 -0
- package/dist/billing/mapping.js +239 -0
- package/dist/billing/openaiCosts.js +352 -0
- package/dist/billing/openaiCostsCoverage.js +108 -0
- package/dist/billing/readiness.js +68 -0
- package/dist/billing/reconcile.js +414 -0
- package/dist/billing/scope.js +68 -0
- package/dist/billing/types.js +180 -0
- package/dist/budget/allocate.js +100 -0
- package/dist/budget/capDecision.js +457 -0
- package/dist/budget/controlLock.js +71 -0
- package/dist/budget/enforceability.js +39 -0
- package/dist/budget/guard.js +313 -0
- package/dist/budget/onlineControl.js +404 -0
- package/dist/budget/recommend.js +153 -0
- package/dist/capital.js +220 -0
- package/dist/causal/assignment.js +179 -0
- package/dist/causal/design.js +161 -0
- package/dist/causal/epistemic.js +428 -0
- package/dist/causal/estimand.js +64 -0
- package/dist/causal/estimate.js +237 -0
- package/dist/causal/family.js +61 -0
- package/dist/causal/identity.js +18 -0
- package/dist/causal/inference-ledger.js +400 -0
- package/dist/causal/ledger.js +201 -0
- package/dist/causal/measurement.js +150 -0
- package/dist/causal/ope.js +297 -0
- package/dist/causal/precision.js +206 -0
- package/dist/causal/producer.js +774 -0
- package/dist/causal/protocol.js +962 -0
- package/dist/causal/qualification.js +260 -0
- package/dist/causal/records.js +416 -0
- package/dist/causal/registry.js +58 -0
- package/dist/causal/sequential.js +679 -0
- package/dist/causal/transport.js +138 -0
- package/dist/causal/types.js +10 -0
- package/dist/cli/allocCmd.js +340 -0
- package/dist/cli/askModelPrices.js +59 -0
- package/dist/cli/backupCmd.js +100 -0
- package/dist/cli/basisLines.js +45 -0
- package/dist/cli/billingCmd.js +1007 -0
- package/dist/cli/capitalCmd.js +65 -0
- package/dist/cli/causalCmd.js +340 -0
- package/dist/cli/connectCmd.js +466 -0
- package/dist/cli/controlCmd.js +341 -0
- package/dist/cli/diagnosticsCmd.js +41 -0
- package/dist/cli/economicCmd.js +384 -0
- package/dist/cli/egressCmd.js +248 -0
- package/dist/cli/evidenceCmd.js +157 -0
- package/dist/cli/featuresCmd.js +53 -0
- package/dist/cli/flags.js +128 -0
- package/dist/cli/homeCmd.js +117 -0
- package/dist/cli/importCmd.js +657 -0
- package/dist/cli/launchCmd.js +90 -0
- package/dist/cli/marketCmd.js +178 -0
- package/dist/cli/opsCmd.js +335 -0
- package/dist/cli/outcomeCmd.js +120 -0
- package/dist/cli/packCmd.js +172 -0
- package/dist/cli/planCmd.js +181 -0
- package/dist/cli/pluginCmd.js +145 -0
- package/dist/cli/pricingDeclareCmd.js +178 -0
- package/dist/cli/quotaCmd.js +190 -0
- package/dist/cli/retention.js +28 -0
- package/dist/cli/runCmd.js +591 -0
- package/dist/cli/showCmd.js +500 -0
- package/dist/cli/teamCmd.js +760 -0
- package/dist/cli/ui.js +128 -0
- package/dist/cli/valueCmd.js +1001 -0
- package/dist/cli.js +628 -0
- package/dist/config.js +677 -0
- package/dist/connect/antigravity.js +310 -0
- package/dist/connect/claudeCode.js +218 -0
- package/dist/connect/codex.js +320 -0
- package/dist/connect/connectors.js +285 -0
- package/dist/connect/importShared.js +283 -0
- package/dist/connect/opencode.js +214 -0
- package/dist/connect/protobuf.js +126 -0
- package/dist/connect/registry.js +46 -0
- package/dist/connect/repoRoot.js +112 -0
- package/dist/cost/basis.js +168 -0
- package/dist/cost/coverage.js +53 -0
- package/dist/cost/declarations.js +37 -0
- package/dist/cost/exactPricing.js +132 -0
- package/dist/cost/firstSight.js +98 -0
- package/dist/cost/overrides.js +230 -0
- package/dist/cost/pricing.js +997 -0
- package/dist/cost/reprice.js +130 -0
- package/dist/dashboard/claim-support.js +271 -0
- package/dist/dashboard/contracts.js +211 -0
- package/dist/dashboard/routes.js +2004 -0
- package/dist/dashboard/server.js +76 -0
- package/dist/dashboard/sessions.js +345 -0
- package/dist/dashboard/settings.js +109 -0
- package/dist/dashboard/shared-types.js +6 -0
- package/dist/dashboard/static.js +111 -0
- package/dist/dashboard/value-cache.js +105 -0
- package/dist/dashboard/web/app/components/claimInspector.js +138 -0
- package/dist/dashboard/web/app/components/drawer.js +284 -0
- package/dist/dashboard/web/app/components/ruleFields.js +144 -0
- package/dist/dashboard/web/app/components/spine.js +163 -0
- package/dist/dashboard/web/app/components/workflow.js +82 -0
- package/dist/dashboard/web/app/core/actions.js +1021 -0
- package/dist/dashboard/web/app/core/api.js +164 -0
- package/dist/dashboard/web/app/core/chain.js +40 -0
- package/dist/dashboard/web/app/core/claimLayers.js +392 -0
- package/dist/dashboard/web/app/core/claimTypes.js +222 -0
- package/dist/dashboard/web/app/core/dom.js +138 -0
- package/dist/dashboard/web/app/core/fmt.js +159 -0
- package/dist/dashboard/web/app/core/focus.js +10 -0
- package/dist/dashboard/web/app/core/generated-contract.js +211 -0
- package/dist/dashboard/web/app/core/generated-payload-contract.js +4579 -0
- package/dist/dashboard/web/app/core/generated-types.js +8 -0
- package/dist/dashboard/web/app/core/griffin.js +10 -0
- package/dist/dashboard/web/app/core/jobs.js +12 -0
- package/dist/dashboard/web/app/core/period.js +35 -0
- package/dist/dashboard/web/app/core/periodWords.js +10 -0
- package/dist/dashboard/web/app/core/periods.js +32 -0
- package/dist/dashboard/web/app/core/pricingActions.js +264 -0
- package/dist/dashboard/web/app/core/privacyText.js +78 -0
- package/dist/dashboard/web/app/core/reconcileWords.js +63 -0
- package/dist/dashboard/web/app/core/registry.js +337 -0
- package/dist/dashboard/web/app/core/signal.js +140 -0
- package/dist/dashboard/web/app/core/slug.js +9 -0
- package/dist/dashboard/web/app/core/theme.js +48 -0
- package/dist/dashboard/web/app/core/view.js +69 -0
- package/dist/dashboard/web/app/main.js +362 -0
- package/dist/dashboard/web/app/views/allocation.js +278 -0
- package/dist/dashboard/web/app/views/control.js +249 -0
- package/dist/dashboard/web/app/views/data.js +136 -0
- package/dist/dashboard/web/app/views/evidence.js +553 -0
- package/dist/dashboard/web/app/views/privacy.js +13 -0
- package/dist/dashboard/web/app/views/spend.js +143 -0
- package/dist/dashboard/web/app/views/statement.js +189 -0
- package/dist/dashboard/web/app/views/system.js +80 -0
- package/dist/dashboard/web/app/views/value.js +534 -0
- package/dist/dashboard/web/app/views/workbench.js +312 -0
- package/dist/dashboard/web/classic.html +2151 -0
- package/dist/dashboard/web/index.html +51 -0
- package/dist/dashboard/web/styles/app.css +1336 -0
- package/dist/decision/assurance.js +425 -0
- package/dist/decision/control.js +336 -0
- package/dist/decision/countermodels.js +118 -0
- package/dist/decision/engine.js +382 -0
- package/dist/decision/epistemic.js +546 -0
- package/dist/demo/seed.js +741 -0
- package/dist/diagnostics.js +236 -0
- package/dist/economics/attribution.js +201 -0
- package/dist/economics/close.js +133 -0
- package/dist/economics/corrections.js +120 -0
- package/dist/economics/epistemic.js +164 -0
- package/dist/economics/events.js +294 -0
- package/dist/economics/fx.js +245 -0
- package/dist/economics/ledger.js +1516 -0
- package/dist/economics/money.js +177 -0
- package/dist/economics/rate.js +331 -0
- package/dist/economics/request.js +89 -0
- package/dist/economics/serialization.js +99 -0
- package/dist/egress/policy.js +192 -0
- package/dist/egress/proxyHealth.js +36 -0
- package/dist/egress/receipts.js +871 -0
- package/dist/egress/ruleValidation.js +127 -0
- package/dist/egress/transport.js +395 -0
- package/dist/epistemic/abstract.js +432 -0
- package/dist/epistemic/admissibility.js +213 -0
- package/dist/epistemic/assumption.js +134 -0
- package/dist/epistemic/claim-uses.js +202 -0
- package/dist/epistemic/claim.js +264 -0
- package/dist/epistemic/countermodel.js +278 -0
- package/dist/epistemic/dag.js +421 -0
- package/dist/epistemic/derivation.js +391 -0
- package/dist/epistemic/evidence.js +254 -0
- package/dist/epistemic/grain.js +82 -0
- package/dist/epistemic/issuance-map.js +260 -0
- package/dist/epistemic/ledger.js +1489 -0
- package/dist/epistemic/obligation.js +149 -0
- package/dist/epistemic/preservation.js +178 -0
- package/dist/epistemic/profile.js +61 -0
- package/dist/epistemic/revocation.js +65 -0
- package/dist/epistemic/scope.js +66 -0
- package/dist/epistemic/serialization.js +171 -0
- package/dist/epistemic/state.js +46 -0
- package/dist/epistemic/time.js +37 -0
- package/dist/epistemic/ux.js +104 -0
- package/dist/epistemic/witness.js +176 -0
- package/dist/export/allocationCsv.js +70 -0
- package/dist/export/billingCsv.js +36 -0
- package/dist/export/csv.js +52 -0
- package/dist/export/economic.js +105 -0
- package/dist/export/focusBilling.js +66 -0
- package/dist/export/statementCsv.js +104 -0
- package/dist/git/completeness.js +78 -0
- package/dist/git/contribution.js +598 -0
- package/dist/git/correlate.js +286 -0
- package/dist/git/quality.js +467 -0
- package/dist/git/repoScope.js +207 -0
- package/dist/git/survivalStore.js +186 -0
- package/dist/githubActionsEvidence.js +234 -0
- package/dist/guide.js +159 -0
- package/dist/judge/call.js +161 -0
- package/dist/judge/orchestrate.js +127 -0
- package/dist/judge/payload.js +47 -0
- package/dist/judge/tier.js +107 -0
- package/dist/judge/transcript.js +324 -0
- package/dist/market/consensus.js +181 -0
- package/dist/market/market.js +323 -0
- package/dist/market/refresh.js +119 -0
- package/dist/market/sources.js +236 -0
- package/dist/market/zip.js +98 -0
- package/dist/measurement/completeness.js +125 -0
- package/dist/measurement/model.js +113 -0
- package/dist/measurement/registry.js +166 -0
- package/dist/measurement/surrogate.js +325 -0
- package/dist/outcomes/contract.js +107 -0
- package/dist/outcomes/registry.js +259 -0
- package/dist/outcomes/work-unit.js +42 -0
- package/dist/pack/canonical.js +63 -0
- package/dist/pack/export.js +120 -0
- package/dist/pack/index.js +5 -0
- package/dist/pack/manifest.js +77 -0
- package/dist/pack/signature.js +69 -0
- package/dist/pack/types.js +455 -0
- package/dist/pack/verifier.js +275 -0
- package/dist/plans/detect.js +147 -0
- package/dist/plugins/contract.js +497 -0
- package/dist/plugins/host.js +333 -0
- package/dist/plugins/index.js +4 -0
- package/dist/plugins/intake.js +137 -0
- package/dist/plugins/invocation.js +158 -0
- package/dist/plugins/isolation.js +203 -0
- package/dist/proxy/server.js +891 -0
- package/dist/proxy/stream-proposals.js +249 -0
- package/dist/proxy/usage.js +213 -0
- package/dist/quota/limits.js +138 -0
- package/dist/quota/statusline.js +68 -0
- package/dist/quota/view.js +122 -0
- package/dist/research/complexity/calibration.js +110 -0
- package/dist/research/complexity/lab.js +134 -0
- package/dist/research/complexity/profile.js +78 -0
- package/dist/research/economics/budgetRisk.js +100 -0
- package/dist/research/economics/capital.js +101 -0
- package/dist/research/economics/decisionLedger.js +103 -0
- package/dist/research/economics/decomposition.js +106 -0
- package/dist/research/economics/execution.js +42 -0
- package/dist/research/economics/frontier.js +113 -0
- package/dist/research/economics/metricSafety.js +74 -0
- package/dist/research/economics/offPolicy.js +120 -0
- package/dist/research/economics/promotion.js +85 -0
- package/dist/scan/knownApps.js +113 -0
- package/dist/scan/scan.js +220 -0
- package/dist/store/allocation.js +543 -0
- package/dist/store/backup.js +368 -0
- package/dist/store/billing.js +919 -0
- package/dist/store/causal.js +2547 -0
- package/dist/store/causalLineage.js +912 -0
- package/dist/store/causalProducer.js +462 -0
- package/dist/store/db.js +2726 -0
- package/dist/store/economicReadModel.js +270 -0
- package/dist/store/ope.js +67 -0
- package/dist/store/realization.js +379 -0
- package/dist/store/rows.js +52 -0
- package/dist/store/schema.js +2218 -0
- package/dist/store/scopeEvidence.js +67 -0
- package/dist/team/ledger-evidence.js +82 -0
- package/dist/team/rollup.js +496 -0
- package/dist/team/standardize.js +115 -0
- package/dist/util/json.js +24 -0
- package/dist/util/pool.js +19 -0
- package/dist/util/quiet.js +18 -0
- package/dist/util/resource-limits.js +113 -0
- package/dist/util/statements.js +61 -0
- package/dist/util/time.js +7 -0
- package/dist/util/transaction.js +68 -0
- package/dist/value/anytime.js +106 -0
- package/dist/value/characterization.js +77 -0
- package/dist/value/cohort.js +212 -0
- package/dist/value/drift.js +211 -0
- package/dist/value/epistemic.js +448 -0
- package/dist/value/frontier.js +513 -0
- package/dist/value/gates.js +276 -0
- package/dist/value/instrumentationSensitivity.js +76 -0
- package/dist/value/lenses.js +398 -0
- package/dist/value/lift.js +206 -0
- package/dist/value/liftBaseline.js +355 -0
- package/dist/value/liftEfficiency.js +68 -0
- package/dist/value/marginal.js +154 -0
- package/dist/value/proposals.js +263 -0
- package/dist/value/realization.js +1159 -0
- package/dist/value/receipt.js +222 -0
- package/dist/value/receiptReconciliation.js +117 -0
- package/dist/value/reliability.js +101 -0
- package/dist/value/report.js +338 -0
- package/dist/value/selfReported.js +224 -0
- package/dist/value/sourceDepth.js +25 -0
- package/dist/value/taskType.js +46 -0
- package/dist/value/timeReclaimed.js +90 -0
- package/dist/value/usage.js +281 -0
- package/dist/version.js +20 -0
- package/docs/ALLOCATION.md +263 -0
- package/docs/ARCHITECTURE.md +452 -0
- package/docs/BILLING-EVIDENCE-IMPORT.md +274 -0
- package/docs/CAPABILITY-EVIDENCE-CONTRACT.md +220 -0
- package/docs/CAUSAL-EVIDENCE-PROTOCOL.md +295 -0
- package/docs/CAUSAL-PRODUCER-CONTRACT.md +128 -0
- package/docs/CLI-JSON-CONTRACT.md +38 -0
- package/docs/COMPATIBILITY.md +64 -0
- package/docs/DATA-BOUNDARIES.md +300 -0
- package/docs/EVIDENCE-PROVENANCE.md +40 -0
- package/docs/FAQ.md +275 -0
- package/docs/FOCUS-COMPATIBILITY.md +15 -0
- package/docs/GETTING-STARTED.md +236 -0
- package/docs/GUIDE.md +830 -0
- package/docs/INTEGRATIONS.md +233 -0
- package/docs/MARKET-SOURCES.md +142 -0
- package/docs/METHODOLOGY.md +166 -0
- package/docs/NEUTRALITY.md +95 -0
- package/docs/PRIVACY.md +51 -0
- package/docs/PROVIDER-RECONCILIATION.md +260 -0
- package/docs/README.md +52 -0
- package/docs/REAL-PROVIDER-RECONCILIATION-RUNBOOK.md +44 -0
- package/docs/RELEASE-GATE.md +682 -0
- package/docs/RELEASE-PROCESS.md +68 -0
- package/docs/RELIABILITY-PERFORMANCE.md +149 -0
- package/docs/RETURN-ON-INTELLIGENCE.md +808 -0
- package/docs/SUPPORT.md +37 -0
- package/docs/THE-STANDARD.md +235 -0
- package/docs/THREAT-MODEL.md +114 -0
- package/market/consensus-fits.json +1 -0
- package/market/snapshot.json +1 -0
- package/package.json +79 -4
- package/pricing/models.json +1400 -0
- package/standalone/segreantpack-verifier.d.mts +61 -0
- package/standalone/segreantpack-verifier.mjs +715 -0
- package/web/assets/brand/mark-256.png +0 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Alert delivery — the "notify" half of governance.
|
|
3
|
+
*
|
|
4
|
+
* Detecting a budget breach is only useful if someone hears about it when they
|
|
5
|
+
* aren't staring at the dashboard. This POSTs alert metadata to a user-configured
|
|
6
|
+
* webhook (their own Slack/Teams/PagerDuty endpoint).
|
|
7
|
+
*
|
|
8
|
+
* Privacy boundary, enforced by construction: the payload is built ONLY from the
|
|
9
|
+
* Alert fields (id, severity, title, detail, metric). There is no code path here
|
|
10
|
+
* that can read a prompt, a response body, source code, or an API key — so the
|
|
11
|
+
* "no prompt or code leaves your device" promise holds even with delivery on.
|
|
12
|
+
*/
|
|
13
|
+
import { discardResponseBody, egressFetch, EgressError } from '../egress/transport.js';
|
|
14
|
+
const SEV_RANK = { info: 0, warn: 1, critical: 2 };
|
|
15
|
+
/** Build the exact payload that would be sent. Pure — used in tests to prove the boundary. */
|
|
16
|
+
export function buildWebhookPayload(alerts, minSeverity = 'warn', now = Date.now()) {
|
|
17
|
+
const min = SEV_RANK[minSeverity];
|
|
18
|
+
return {
|
|
19
|
+
source: 'segreant',
|
|
20
|
+
generatedAt: new Date(now).toISOString(),
|
|
21
|
+
alerts: alerts
|
|
22
|
+
.filter((a) => SEV_RANK[a.severity] >= min)
|
|
23
|
+
.map((a) => ({ id: a.id, severity: a.severity, title: a.title, detail: a.detail, metric: a.metric })),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function egressRepairAction(code) {
|
|
27
|
+
if (code === 'receipt_integrity_failed' || code === 'receipt_persistence_failed') {
|
|
28
|
+
return 'restore or repair the local egress receipt history, then retry; if a lock is stale, confirm no Segreant writer owns it and remove only that lock';
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* POST the alert metadata to `url`. Fire-and-forget with a timeout; a failed
|
|
34
|
+
* delivery never throws (governance must not depend on a reachable webhook).
|
|
35
|
+
*/
|
|
36
|
+
export async function notifyWebhook(url, alerts, opts = {}) {
|
|
37
|
+
const payload = buildWebhookPayload(alerts, opts.minSeverity ?? 'warn', opts.now);
|
|
38
|
+
if (payload.alerts.length === 0)
|
|
39
|
+
return { delivered: false, posted: 0 };
|
|
40
|
+
try {
|
|
41
|
+
const res = await egressFetch(url, {
|
|
42
|
+
purpose: 'alert_delivery',
|
|
43
|
+
dataClass: 'alert_metadata',
|
|
44
|
+
method: 'POST',
|
|
45
|
+
headers: { 'content-type': 'application/json' },
|
|
46
|
+
body: JSON.stringify(payload),
|
|
47
|
+
signal: AbortSignal.timeout(opts.timeoutMs ?? 4000),
|
|
48
|
+
});
|
|
49
|
+
const delivered = res.ok;
|
|
50
|
+
const status = res.status;
|
|
51
|
+
await discardResponseBody(res);
|
|
52
|
+
return { delivered, posted: payload.alerts.length, status };
|
|
53
|
+
}
|
|
54
|
+
catch (e) {
|
|
55
|
+
if (e instanceof EgressError) {
|
|
56
|
+
return {
|
|
57
|
+
delivered: false,
|
|
58
|
+
posted: payload.alerts.length,
|
|
59
|
+
error: e.message,
|
|
60
|
+
failureCode: e.code,
|
|
61
|
+
action: egressRepairAction(e.code),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
return { delivered: false, posted: payload.alerts.length, error: String(e), failureCode: 'network_error' };
|
|
65
|
+
}
|
|
66
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exact allocation-to-kernel issuance adapter.
|
|
3
|
+
*
|
|
4
|
+
* ISSUANCE CLASS: canonical — see `src/epistemic/issuance-map.ts`.
|
|
5
|
+
*/
|
|
6
|
+
import { claim } from '../epistemic/claim.js';
|
|
7
|
+
import { evidence } from '../epistemic/evidence.js';
|
|
8
|
+
import { grain } from '../epistemic/grain.js';
|
|
9
|
+
import { scope } from '../epistemic/scope.js';
|
|
10
|
+
import { instant, interval } from '../epistemic/time.js';
|
|
11
|
+
import { canonicalPeriod } from '../economics/close.js';
|
|
12
|
+
import { ECONOMIC_BASES } from '../economics/money.js';
|
|
13
|
+
import { exactAllocationClaimProfile, exactAllocationToJson, serializeExactAllocationRun, validateExactAllocationResult } from './exact.js';
|
|
14
|
+
const ALLOCATION_ASSUMPTIONS = Object.freeze([
|
|
15
|
+
'Allocation is a derived local showback projection, not provider settlement, chargeback, or causal attribution.',
|
|
16
|
+
'The exact input event set and its pricing bases are retained in the allocation result; unresolved legacy requests remain outside the exact rows.',
|
|
17
|
+
]);
|
|
18
|
+
function computedAt(value) {
|
|
19
|
+
if (!Number.isSafeInteger(value))
|
|
20
|
+
throw new Error('exact allocation computedAt must be a safe integer timestamp');
|
|
21
|
+
const iso = new Date(value).toISOString();
|
|
22
|
+
if (Date.parse(iso) !== value)
|
|
23
|
+
throw new Error('exact allocation computedAt is outside the supported timestamp range');
|
|
24
|
+
return instant(iso);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* A MONETARY BASIS THAT OMITS ITS UNIT IS NOT A BASIS (WP-C03 / D-200).
|
|
28
|
+
*
|
|
29
|
+
* `sourceBases` is a basis-only summary, so a run holding USD 10.00 and
|
|
30
|
+
* EUR 90.00 — both at the `effective` basis — collapses to exactly one entry
|
|
31
|
+
* and this declared `monetaryBasis: 'effective'` for a kernel Evidence record
|
|
32
|
+
* spanning two currencies. The allocation figures underneath were never wrong:
|
|
33
|
+
* `applyExactAllocation` partitions every bucket and line by currency+basis
|
|
34
|
+
* identity and never sums across them. What was wrong is the one field a reader
|
|
35
|
+
* consults to learn what unit the claim is in.
|
|
36
|
+
*
|
|
37
|
+
* The honest answer for a multi-currency run is that there is no single
|
|
38
|
+
* monetary basis, which is what `null` already means here for a multi-basis
|
|
39
|
+
* run. Normalizing instead would require a target currency and an as-of
|
|
40
|
+
* boundary that an allocation run does not have — and choosing a rate without
|
|
41
|
+
* one is the failure the effective-FX read model exists to prevent. The
|
|
42
|
+
* per-identity totals remain in the payload, so nothing is withheld except the
|
|
43
|
+
* false summary.
|
|
44
|
+
*/
|
|
45
|
+
function sourceBasis(result) {
|
|
46
|
+
if (result.sourceBases.length !== 1)
|
|
47
|
+
return null;
|
|
48
|
+
if (new Set(result.totalByIdentity.map((bucket) => bucket.currency)).size > 1)
|
|
49
|
+
return null;
|
|
50
|
+
const basis = result.sourceBases[0];
|
|
51
|
+
if (basis === undefined || !ECONOMIC_BASES.includes(basis))
|
|
52
|
+
throw new Error(`exact allocation source basis is invalid: ${String(basis)}`);
|
|
53
|
+
return basis;
|
|
54
|
+
}
|
|
55
|
+
function validateRecord(allocationRunId, result) {
|
|
56
|
+
if (typeof allocationRunId !== 'string' || allocationRunId.trim().length === 0)
|
|
57
|
+
throw new Error('exact allocation run ID is required');
|
|
58
|
+
validateExactAllocationResult(result);
|
|
59
|
+
const serialized = serializeExactAllocationRun(result);
|
|
60
|
+
const expectedId = `economic:allocation:${serialized.digest.slice('sha256:'.length)}`;
|
|
61
|
+
if (allocationRunId !== expectedId)
|
|
62
|
+
throw new Error('exact allocation run ID does not match its canonical result digest');
|
|
63
|
+
const period = canonicalPeriod(result.periodStartMs, result.periodEndMs);
|
|
64
|
+
return { period, serialized, observedAt: computedAt(result.runAtMs), recordedAt: computedAt(result.runAtMs) };
|
|
65
|
+
}
|
|
66
|
+
/** Build immutable kernel Evidence/Claim records for one persisted exact run. */
|
|
67
|
+
export function buildExactAllocationKernelIssuance(allocationRunId, result, computedAtMs) {
|
|
68
|
+
const { period, serialized, recordedAt } = validateRecord(allocationRunId, result);
|
|
69
|
+
const computed = computedAt(computedAtMs);
|
|
70
|
+
const validTime = interval(period.start, period.end);
|
|
71
|
+
const allocationScope = scope({ ledger: 'segreant-economic', period: period.subject, allocationRunId });
|
|
72
|
+
const allocationJson = exactAllocationToJson(result);
|
|
73
|
+
const payload = {
|
|
74
|
+
allocationRunId,
|
|
75
|
+
periodStartMs: period.startMs,
|
|
76
|
+
periodEndMs: period.endMs,
|
|
77
|
+
runAtMs: result.runAtMs,
|
|
78
|
+
computedAtMs,
|
|
79
|
+
result: allocationJson,
|
|
80
|
+
resultDigest: serialized.digest,
|
|
81
|
+
};
|
|
82
|
+
const coverage = result.complete ? 'complete' : 'partial';
|
|
83
|
+
const evidenceValue = evidence({
|
|
84
|
+
id: `evidence:economic:allocation:${allocationRunId}`,
|
|
85
|
+
evidenceType: 'economic.allocation',
|
|
86
|
+
sourceIdentity: 'segreant:economic-allocation',
|
|
87
|
+
sourceClass: 'segreant_local_exact_allocation_projection',
|
|
88
|
+
payload,
|
|
89
|
+
scope: allocationScope,
|
|
90
|
+
grain: grain(['economic_period', 'cost_centre']),
|
|
91
|
+
occurredAt: period.end,
|
|
92
|
+
validTime,
|
|
93
|
+
observedAt: recordedAt,
|
|
94
|
+
recordedAt: computed,
|
|
95
|
+
assertedAt: computed,
|
|
96
|
+
finalizedAt: null,
|
|
97
|
+
integrity: 'verified',
|
|
98
|
+
authenticity: 'self_asserted',
|
|
99
|
+
completeness: {
|
|
100
|
+
status: coverage,
|
|
101
|
+
method: 'exact_allocation_projection',
|
|
102
|
+
coveredEventTypes: ['economic_event', 'economic_allocation'],
|
|
103
|
+
coveredScope: allocationScope,
|
|
104
|
+
coveredTime: validTime,
|
|
105
|
+
},
|
|
106
|
+
measurementModelRef: null,
|
|
107
|
+
monetaryBasis: sourceBasis(result),
|
|
108
|
+
assumptions: ALLOCATION_ASSUMPTIONS,
|
|
109
|
+
supersedes: [],
|
|
110
|
+
supersededBy: null,
|
|
111
|
+
revocation: null,
|
|
112
|
+
schemaVersion: 1,
|
|
113
|
+
sensitivity: 'internal',
|
|
114
|
+
redaction: 'none',
|
|
115
|
+
});
|
|
116
|
+
const claimValue = {
|
|
117
|
+
allocationRunId,
|
|
118
|
+
periodStartMs: period.startMs,
|
|
119
|
+
periodEndMs: period.endMs,
|
|
120
|
+
resultDigest: serialized.digest,
|
|
121
|
+
complete: result.complete,
|
|
122
|
+
conserves: result.conserves,
|
|
123
|
+
sourceBases: [...result.sourceBases],
|
|
124
|
+
unresolvedRequestIds: [...result.unresolvedRequestIds],
|
|
125
|
+
result: allocationJson,
|
|
126
|
+
};
|
|
127
|
+
const claimValueRecord = claim({
|
|
128
|
+
id: `claim:economic:allocation:${allocationRunId}`,
|
|
129
|
+
proposition: { predicate: 'economic.allocation_recorded', value: claimValue },
|
|
130
|
+
subject: allocationRunId,
|
|
131
|
+
scope: allocationScope,
|
|
132
|
+
grain: grain(['economic_period', 'cost_centre']),
|
|
133
|
+
time: { validTime, asOf: computed },
|
|
134
|
+
epistemic: 'supported',
|
|
135
|
+
// The same profile the run's `excludedFrom` was derived from (D-228).
|
|
136
|
+
profile: exactAllocationClaimProfile(result.complete),
|
|
137
|
+
measurementModelRef: null,
|
|
138
|
+
evidenceIds: [evidenceValue.id],
|
|
139
|
+
derivationRule: 'economic.allocation.v1',
|
|
140
|
+
derivationVersion: 1,
|
|
141
|
+
assumptions: ALLOCATION_ASSUMPTIONS,
|
|
142
|
+
uncertainty: { kind: 'qualitative', description: 'Exact arithmetic and source lineage are verified; allocation is a local derived showback, not provider billing or causal value.' },
|
|
143
|
+
causalStatus: 'none',
|
|
144
|
+
monetaryBasis: 'allocated',
|
|
145
|
+
finality: 'provisional',
|
|
146
|
+
issuedAt: computed,
|
|
147
|
+
supersedes: [],
|
|
148
|
+
supersededBy: null,
|
|
149
|
+
revocation: null,
|
|
150
|
+
decisionCertificateIds: [],
|
|
151
|
+
schemaVersion: 1,
|
|
152
|
+
});
|
|
153
|
+
return Object.freeze({ evidence: evidenceValue, claim: claimValueRecord });
|
|
154
|
+
}
|