onto-mcp 0.4.12 → 0.4.13
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/.onto/authority/core-lexicon.yaml +1 -1
- package/.onto/authority/supported-models.yaml +137 -0
- package/.onto/domains/accounting-kr/competency_qs.md +153 -153
- package/.onto/processes/reconstruct/obligation-coverage-ledger.yaml +842 -0
- package/.onto/processes/reconstruct/obligation-coverage-recorded.yaml +225 -0
- package/.onto/processes/reconstruct/ontology-seeding-and-maturation-design.md +93 -54
- package/.onto/processes/reconstruct/reconstruct-contract-registry.yaml +169 -8
- package/.onto/processes/reconstruct/reconstruct-execution-ux-contract.md +72 -1
- package/.onto/processes/reconstruct/source-profiles/spreadsheet.md +35 -0
- package/.onto/processes/review/productized-live-path.md +9 -5
- package/.onto/processes/review/prompt-execution-runner-contract.md +32 -8
- package/.onto/processes/review/review-target-profile-contract.md +47 -4
- package/.onto/processes/shared/pipeline-execution-ledger-contract.md +11 -0
- package/.onto/processes/shared/target-material-kind-contract.md +1 -1
- package/README.md +64 -1
- package/dist/cli.js +11 -1
- package/dist/core-api/reconstruct-api.js +575 -24
- package/dist/core-api/review-api.js +70 -5
- package/dist/core-api/review-progress.js +7 -0
- package/dist/core-api/runtime-observation.js +7 -0
- package/dist/core-runtime/artifact-io.js +75 -3
- package/dist/core-runtime/cli/claude-code-review-unit-executor.js +19 -8
- package/dist/core-runtime/cli/materialize-review-prompt-packets.js +68 -14
- package/dist/core-runtime/cli/prepare-review-session.js +34 -1
- package/dist/core-runtime/cli/render-review-final-output.js +2 -1
- package/dist/core-runtime/cli/run-review-prompt-execution.js +758 -48
- package/dist/core-runtime/cli/run-seats.js +18 -0
- package/dist/core-runtime/cli/runtime-submit-context.js +10 -2
- package/dist/core-runtime/cli/unit-resubmit.js +269 -0
- package/dist/core-runtime/cli/worker-structured-output.js +80 -2
- package/dist/core-runtime/discovery/host-detection.js +71 -22
- package/dist/core-runtime/discovery/review-cert-assemble.js +208 -0
- package/dist/core-runtime/discovery/review-cert-record.js +442 -0
- package/dist/core-runtime/discovery/review-execution-units.js +22 -0
- package/dist/core-runtime/discovery/seat-inventory.js +167 -0
- package/dist/core-runtime/discovery/settings-chain.js +311 -52
- package/dist/core-runtime/discovery/supported-models.js +282 -29
- package/dist/core-runtime/discovery/synthesize-cert-assemble.js +197 -0
- package/dist/core-runtime/discovery/synthesize-cert-capsule.js +399 -0
- package/dist/core-runtime/discovery/synthesize-cert-judge.js +340 -0
- package/dist/core-runtime/discovery/synthesize-cert-loop.js +234 -0
- package/dist/core-runtime/discovery/synthesize-cert-mutation.js +117 -0
- package/dist/core-runtime/discovery/synthesize-cert-packet.js +182 -0
- package/dist/core-runtime/discovery/synthesize-cert-record.js +831 -0
- package/dist/core-runtime/discovery/synthesize-cert-sampler.js +336 -0
- package/dist/core-runtime/effort-calibration-ingest.js +135 -0
- package/dist/core-runtime/llm/dispatch-breaker.js +412 -0
- package/dist/core-runtime/llm/dispatch-fallback-adapter-capabilities.js +33 -0
- package/dist/core-runtime/llm/llm-caller.js +188 -47
- package/dist/core-runtime/llm/mock-llm-realization.js +35 -4
- package/dist/core-runtime/llm/model-switcher.js +1 -1
- package/dist/core-runtime/llm/openai-responses-incomplete-error.js +46 -0
- package/dist/core-runtime/llm/sealed-dispatch-capability.js +359 -0
- package/dist/core-runtime/llm/structured-dispatch-error.js +15 -0
- package/dist/core-runtime/onboard/claude-profile-scan.js +65 -0
- package/dist/core-runtime/onboard/cli-host.js +5 -2
- package/dist/core-runtime/onboard/configure-provider.js +33 -1
- package/dist/core-runtime/onboard/host-target.js +28 -3
- package/dist/core-runtime/onboard/register.js +54 -12
- package/dist/core-runtime/pipeline-execution-ledger.js +10 -0
- package/dist/core-runtime/reconstruct/artifact-types.js +35 -0
- package/dist/core-runtime/reconstruct/claim-projection-validation.js +17 -0
- package/dist/core-runtime/reconstruct/competency-projection-contract.js +63 -0
- package/dist/core-runtime/reconstruct/comprehension-artifact.js +321 -0
- package/dist/core-runtime/reconstruct/comprehension-reduce.js +367 -0
- package/dist/core-runtime/reconstruct/comprehension-semantic-map.js +771 -0
- package/dist/core-runtime/reconstruct/contract-registry.js +20 -0
- package/dist/core-runtime/reconstruct/dispatch-fallback-artifacts.js +640 -0
- package/dist/core-runtime/reconstruct/execution-telemetry.js +83 -9
- package/dist/core-runtime/reconstruct/final-output-sections.js +89 -0
- package/dist/core-runtime/reconstruct/governing-snapshot.js +36 -1
- package/dist/core-runtime/reconstruct/leaf-reader.js +305 -0
- package/dist/core-runtime/reconstruct/llm-dispatch-failure.js +270 -0
- package/dist/core-runtime/reconstruct/llm-touch-fingerprint.js +94 -0
- package/dist/core-runtime/reconstruct/material-admission-validation.js +18 -0
- package/dist/core-runtime/reconstruct/material-profile-validation.js +14 -0
- package/dist/core-runtime/reconstruct/materialize-preparation.js +304 -18
- package/dist/core-runtime/reconstruct/maturation-validation.js +1231 -53
- package/dist/core-runtime/reconstruct/mock-llm-realization.js +107 -3
- package/dist/core-runtime/reconstruct/obligation-assertion.js +18 -0
- package/dist/core-runtime/reconstruct/ontology-seed-validation.js +27 -0
- package/dist/core-runtime/reconstruct/output-budget.js +6 -0
- package/dist/core-runtime/reconstruct/pipeline-execution-ledger.js +87 -3
- package/dist/core-runtime/reconstruct/post-seed-validation.js +118 -5
- package/dist/core-runtime/reconstruct/purpose-authority-validation.js +117 -2
- package/dist/core-runtime/reconstruct/record.js +42 -0
- package/dist/core-runtime/reconstruct/registry-verification-validation.js +16 -0
- package/dist/core-runtime/reconstruct/run-control-validation.js +1011 -34
- package/dist/core-runtime/reconstruct/run.js +5198 -536
- package/dist/core-runtime/reconstruct/seed-authoring-readiness-validation.js +54 -3
- package/dist/core-runtime/reconstruct/semantic-quality-gate.js +105 -2
- package/dist/core-runtime/reconstruct/source-observation-delta-validation.js +41 -0
- package/dist/core-runtime/reconstruct/source-observations.js +166 -0
- package/dist/core-runtime/reconstruct/source-safety-validation.js +71 -183
- package/dist/core-runtime/reconstruct/source-scout-pack-validation.js +37 -1
- package/dist/core-runtime/reconstruct/terminal-validation.js +132 -2
- package/dist/core-runtime/review/continuation-plan.js +12 -5
- package/dist/core-runtime/review/issue-artifact-runtime.js +4 -1
- package/dist/core-runtime/review/materializers.js +100 -11
- package/dist/core-runtime/review/nesting-batch.js +6 -2
- package/dist/core-runtime/review/obligation-shardability.js +138 -0
- package/dist/core-runtime/review/pipeline-execution-ledger.js +42 -2
- package/dist/core-runtime/review/review-artifact-utils.js +217 -5
- package/dist/core-runtime/review/review-execution-steps.js +32 -8
- package/dist/core-runtime/review/review-progress-contract.js +8 -0
- package/dist/core-runtime/review/review-prompt-budget.js +97 -0
- package/dist/core-runtime/review/semantic-quality-gate.js +33 -7
- package/dist/core-runtime/review/spreadsheet-review-disposition.js +94 -0
- package/dist/core-runtime/route-identity.js +182 -0
- package/dist/core-runtime/spreadsheet-header-escalation.js +204 -0
- package/dist/core-runtime/spreadsheet-structure-observer.js +2689 -0
- package/dist/core-runtime/target-material-kind.js +58 -0
- package/dist/mcp/server.js +12 -5
- package/dist/tui/app.js +167 -0
- package/dist/tui/data/event-follower.js +116 -0
- package/dist/tui/data/node-detail.js +42 -0
- package/dist/tui/data/projection-poll.js +26 -0
- package/dist/tui/data/session-discovery.js +65 -0
- package/dist/tui/index.js +108 -0
- package/dist/tui/screens/log.js +25 -0
- package/dist/tui/screens/node-detail.js +17 -0
- package/dist/tui/screens/session-selector.js +26 -0
- package/dist/tui/screens/workflow-tree.js +90 -0
- package/dist/tui/view-model/reconstruct-adapter.js +162 -0
- package/dist/tui/view-model/review-adapter.js +270 -0
- package/dist/tui/view-model/tree-view-model.js +19 -0
- package/package.json +18 -3
- package/settings.example.json +77 -16
|
@@ -3,11 +3,10 @@ import fs from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { parse as parseYaml } from "yaml";
|
|
5
5
|
import { assertArrayField, atomicWriteYamlDocument as writeYamlDocument } from "../artifact-io.js";
|
|
6
|
+
import { assertObligation } from "./obligation-assertion.js";
|
|
6
7
|
const SOURCE_SAFETY_CANONICAL_AXES = [
|
|
7
8
|
"lifecycle_state",
|
|
8
9
|
"authorization_state",
|
|
9
|
-
"privacy_state",
|
|
10
|
-
"redaction_state",
|
|
11
10
|
"proof_sufficiency_state",
|
|
12
11
|
"replay_state",
|
|
13
12
|
];
|
|
@@ -28,26 +27,13 @@ const AUTHORIZATION_STATES = [
|
|
|
28
27
|
"unknown",
|
|
29
28
|
"not_required",
|
|
30
29
|
];
|
|
31
|
-
const PRIVACY_STATES = [
|
|
32
|
-
"non_sensitive",
|
|
33
|
-
"privacy_sensitive",
|
|
34
|
-
"unknown",
|
|
35
|
-
];
|
|
36
|
-
const REDACTION_STATES = [
|
|
37
|
-
"none",
|
|
38
|
-
"redacted",
|
|
39
|
-
"required",
|
|
40
|
-
"insufficient",
|
|
41
|
-
];
|
|
42
30
|
const PROOF_SUFFICIENCY_STATES = [
|
|
43
31
|
"sufficient_for_claim",
|
|
44
32
|
"insufficient_for_claim",
|
|
45
|
-
"trace_only",
|
|
46
33
|
"unavailable",
|
|
47
34
|
];
|
|
48
35
|
const REPLAY_STATES = [
|
|
49
36
|
"replay_allowed",
|
|
50
|
-
"replay_with_redaction",
|
|
51
37
|
"no_replay_use",
|
|
52
38
|
"unknown",
|
|
53
39
|
];
|
|
@@ -61,32 +47,9 @@ const INTENDED_CONSUMPTIONS = [
|
|
|
61
47
|
const VISIBILITY_TIERS = [
|
|
62
48
|
"consumption_allowed",
|
|
63
49
|
"internal_only",
|
|
64
|
-
"redacted_output_only",
|
|
65
50
|
"no_prompt_use",
|
|
66
51
|
"no_replay_use",
|
|
67
52
|
];
|
|
68
|
-
const ALLOWED_PROOF_FORMS = [
|
|
69
|
-
"raw_value",
|
|
70
|
-
"hash",
|
|
71
|
-
"bounded_summary",
|
|
72
|
-
"source_ref_only",
|
|
73
|
-
"unavailable",
|
|
74
|
-
];
|
|
75
|
-
const SAFE_REDACTED_PROOF_FORMS = new Set([
|
|
76
|
-
"hash",
|
|
77
|
-
"bounded_summary",
|
|
78
|
-
"source_ref_only",
|
|
79
|
-
]);
|
|
80
|
-
const SENSITIVE_SOURCE_PATTERNS = [
|
|
81
|
-
/-----BEGIN (?:RSA |EC |OPENSSH |DSA |PGP )?PRIVATE KEY-----/,
|
|
82
|
-
/\b(?:api[_-]?key|secret|password|passwd|pwd|token)\b\s*[:=]\s*['"]?[^'"\s]{8,}/i,
|
|
83
|
-
/\bAuthorization:\s*Bearer\s+[A-Za-z0-9._~+/=-]{12,}/i,
|
|
84
|
-
/\b(?:AKIA|ASIA)[A-Z0-9]{16}\b/,
|
|
85
|
-
/\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/i,
|
|
86
|
-
/\b\d{3}-\d{2}-\d{4}\b/,
|
|
87
|
-
/\b\d{6}-[1-4]\d{6}\b/,
|
|
88
|
-
/\b(?:\+?\d{1,3}[-.\s]?)?(?:\(?\d{2,4}\)?[-.\s]?)\d{3,4}[-.\s]?\d{4}\b/,
|
|
89
|
-
];
|
|
90
53
|
function isoNow() {
|
|
91
54
|
return new Date().toISOString();
|
|
92
55
|
}
|
|
@@ -107,24 +70,9 @@ function violation(args) {
|
|
|
107
70
|
function inList(value, allowed) {
|
|
108
71
|
return typeof value === "string" && allowed.includes(value);
|
|
109
72
|
}
|
|
110
|
-
function arrayValues(value, allowed) {
|
|
111
|
-
if (!Array.isArray(value))
|
|
112
|
-
return [];
|
|
113
|
-
return value.filter((item) => inList(item, allowed));
|
|
114
|
-
}
|
|
115
73
|
export function sourceSafetyRowIdForObservation(observation, intendedConsumption = "prompt_context") {
|
|
116
74
|
return `source_safety:${observation.observation_id}:${intendedConsumption}`;
|
|
117
75
|
}
|
|
118
|
-
function observationContentExcerpt(observation) {
|
|
119
|
-
const excerpt = observation.structural_data.content_excerpt;
|
|
120
|
-
return typeof excerpt === "string" ? excerpt : null;
|
|
121
|
-
}
|
|
122
|
-
function hasSensitiveSourceEvidence(observation) {
|
|
123
|
-
const excerpt = observationContentExcerpt(observation);
|
|
124
|
-
if (!excerpt)
|
|
125
|
-
return false;
|
|
126
|
-
return SENSITIVE_SOURCE_PATTERNS.some((pattern) => pattern.test(excerpt));
|
|
127
|
-
}
|
|
128
76
|
function explicitConsumptionAuthorizations(observation) {
|
|
129
77
|
const rawAuthorizations = observation.structural_data.source_safety_consumption_authorizations;
|
|
130
78
|
if (!Array.isArray(rawAuthorizations))
|
|
@@ -144,9 +92,6 @@ function stableRuleRef(row) {
|
|
|
144
92
|
.slice(0, 16);
|
|
145
93
|
return `source-safety-visibility-v1:${digest}`;
|
|
146
94
|
}
|
|
147
|
-
function hasSafeRedactedProofForm(row) {
|
|
148
|
-
return row.redaction_evidence.allowed_proof_forms.some((form) => SAFE_REDACTED_PROOF_FORMS.has(form));
|
|
149
|
-
}
|
|
150
95
|
export function deriveSourceSafetyVisibilityTier(row) {
|
|
151
96
|
const intendedConsumption = row.visibility_derivation.intended_consumption;
|
|
152
97
|
if (intendedConsumption === "replay" &&
|
|
@@ -159,9 +104,7 @@ export function deriveSourceSafetyVisibilityTier(row) {
|
|
|
159
104
|
row.authorization_state === "unknown") {
|
|
160
105
|
return "no_prompt_use";
|
|
161
106
|
}
|
|
162
|
-
if (row.proof_sufficiency_state === "unavailable"
|
|
163
|
-
row.redaction_state === "insufficient" ||
|
|
164
|
-
row.redaction_evidence.allowed_proof_forms.includes("unavailable")) {
|
|
107
|
+
if (row.proof_sufficiency_state === "unavailable") {
|
|
165
108
|
return "no_prompt_use";
|
|
166
109
|
}
|
|
167
110
|
if (intendedConsumption === "material_claim" &&
|
|
@@ -172,15 +115,6 @@ export function deriveSourceSafetyVisibilityTier(row) {
|
|
|
172
115
|
row.proof_sufficiency_state !== "sufficient_for_claim") {
|
|
173
116
|
return "internal_only";
|
|
174
117
|
}
|
|
175
|
-
if (row.redaction_state === "redacted" ||
|
|
176
|
-
row.redaction_state === "required" ||
|
|
177
|
-
row.replay_state === "replay_with_redaction" ||
|
|
178
|
-
row.privacy_state === "privacy_sensitive") {
|
|
179
|
-
return hasSafeRedactedProofForm(row) ? "redacted_output_only" : "internal_only";
|
|
180
|
-
}
|
|
181
|
-
if (row.privacy_state === "unknown") {
|
|
182
|
-
return hasSafeRedactedProofForm(row) ? "redacted_output_only" : "internal_only";
|
|
183
|
-
}
|
|
184
118
|
if (intendedConsumption === "public_output" ||
|
|
185
119
|
intendedConsumption === "prompt_context" ||
|
|
186
120
|
intendedConsumption === "material_claim") {
|
|
@@ -189,40 +123,29 @@ export function deriveSourceSafetyVisibilityTier(row) {
|
|
|
189
123
|
return "internal_only";
|
|
190
124
|
}
|
|
191
125
|
function buildSafetyRowForObservation(observation, intendedConsumption) {
|
|
192
|
-
const sensitive = hasSensitiveSourceEvidence(observation);
|
|
193
|
-
const excerpt = observationContentExcerpt(observation);
|
|
194
126
|
const explicitlyAuthorized = explicitConsumptionAuthorizations(observation)
|
|
195
127
|
.has(intendedConsumption);
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
128
|
+
// Defect-3 basis A (runtime-target provenance): a user-provided reconstruct
|
|
129
|
+
// runtime-target source authorizes the outward tiers (material_claim,
|
|
130
|
+
// public_output) by provenance. Scoped to the two upper tiers only — the
|
|
131
|
+
// internal tiers are already covered by runtimeInternalConsumption, and a
|
|
132
|
+
// non-target observation (is_runtime_target_source absent/false) never gets
|
|
133
|
+
// basis A, so this cannot leak to frontier-discovered sources.
|
|
134
|
+
const provenanceAuthorized = observation.is_runtime_target_source === true &&
|
|
135
|
+
(intendedConsumption === "material_claim" ||
|
|
136
|
+
intendedConsumption === "public_output");
|
|
137
|
+
const consumptionAuthorized = runtimeInternalConsumption(intendedConsumption) || explicitlyAuthorized ||
|
|
138
|
+
provenanceAuthorized;
|
|
204
139
|
const rowBase = {
|
|
205
140
|
safety_row_id: sourceSafetyRowIdForObservation(observation, intendedConsumption),
|
|
206
141
|
subject_ref: observation.source_ref,
|
|
207
142
|
subject_kind: "source_ref",
|
|
208
143
|
lifecycle_state: "active",
|
|
209
144
|
authorization_state: consumptionAuthorized ? "authorized" : "unknown",
|
|
210
|
-
|
|
211
|
-
? "
|
|
212
|
-
:
|
|
213
|
-
|
|
214
|
-
: "unknown",
|
|
215
|
-
redaction_state: sensitive ? "required" : consumptionAuthorized ? "none" : "insufficient",
|
|
216
|
-
proof_sufficiency_state: sensitive
|
|
217
|
-
? "trace_only"
|
|
218
|
-
: consumptionAuthorized
|
|
219
|
-
? "sufficient_for_claim"
|
|
220
|
-
: "insufficient_for_claim",
|
|
221
|
-
replay_state: sensitive
|
|
222
|
-
? "replay_with_redaction"
|
|
223
|
-
: consumptionAuthorized
|
|
224
|
-
? "replay_allowed"
|
|
225
|
-
: "unknown",
|
|
145
|
+
proof_sufficiency_state: consumptionAuthorized
|
|
146
|
+
? "sufficient_for_claim"
|
|
147
|
+
: "insufficient_for_claim",
|
|
148
|
+
replay_state: consumptionAuthorized ? "replay_allowed" : "unknown",
|
|
226
149
|
visibility_tier: "internal_only",
|
|
227
150
|
visibility_derivation: {
|
|
228
151
|
intended_consumption: intendedConsumption,
|
|
@@ -237,11 +160,6 @@ function buildSafetyRowForObservation(observation, intendedConsumption) {
|
|
|
237
160
|
? "source_safety_explicit_consumption_authorization"
|
|
238
161
|
: "runtime_target_ref_read_scope"
|
|
239
162
|
: null,
|
|
240
|
-
redaction_evidence: {
|
|
241
|
-
raw_value_available: excerpt !== null,
|
|
242
|
-
allowed_proof_forms: allowedProofForms,
|
|
243
|
-
redaction_rule_ref: sensitive ? "source-safety-sensitive-source-pattern-v1" : null,
|
|
244
|
-
},
|
|
245
163
|
tombstone: {
|
|
246
164
|
tombstone_ref: null,
|
|
247
165
|
reason: null,
|
|
@@ -249,9 +167,6 @@ function buildSafetyRowForObservation(observation, intendedConsumption) {
|
|
|
249
167
|
downstream_refs: [],
|
|
250
168
|
},
|
|
251
169
|
limitation_refs: [
|
|
252
|
-
...(sensitive
|
|
253
|
-
? [`source-safety-sensitive-source:${observation.observation_id}`]
|
|
254
|
-
: []),
|
|
255
170
|
...(!consumptionAuthorized
|
|
256
171
|
? [
|
|
257
172
|
`source-safety-consumption-authorization-gap:${observation.observation_id}:${intendedConsumption}`,
|
|
@@ -296,55 +211,8 @@ function validateCanonicalAxes(args) {
|
|
|
296
211
|
SOURCE_SAFETY_CANONICAL_AXES.some((axis) => !axisSet.has(axis))) {
|
|
297
212
|
args.violations.push(violation({
|
|
298
213
|
code: "visibility_axis_set_invalid",
|
|
299
|
-
message: "visibility_derivation.derived_from_axes must contain exactly the
|
|
300
|
-
subjectId: args.row.safety_row_id,
|
|
301
|
-
}));
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
function validateSupportingDetailConsistency(args) {
|
|
305
|
-
if (args.row.redaction_state !== "none" &&
|
|
306
|
-
args.row.redaction_evidence.allowed_proof_forms.includes("raw_value")) {
|
|
307
|
-
args.violations.push(violation({
|
|
308
|
-
code: "supporting_detail_contradiction",
|
|
309
|
-
message: "redaction_evidence.allowed_proof_forms cannot grant raw_value when top-level redaction_state requires or applies redaction",
|
|
310
|
-
subjectId: args.row.safety_row_id,
|
|
311
|
-
axis: "redaction_state",
|
|
312
|
-
}));
|
|
313
|
-
}
|
|
314
|
-
if (args.row.redaction_state === "none" &&
|
|
315
|
-
args.row.redaction_evidence.redaction_rule_ref) {
|
|
316
|
-
args.violations.push(violation({
|
|
317
|
-
code: "supporting_detail_contradiction",
|
|
318
|
-
message: "redaction_evidence.redaction_rule_ref must be null when top-level redaction_state is none",
|
|
319
|
-
subjectId: args.row.safety_row_id,
|
|
320
|
-
axis: "redaction_state",
|
|
321
|
-
}));
|
|
322
|
-
}
|
|
323
|
-
if (args.row.proof_sufficiency_state === "unavailable" &&
|
|
324
|
-
!args.row.redaction_evidence.allowed_proof_forms.includes("unavailable")) {
|
|
325
|
-
args.violations.push(violation({
|
|
326
|
-
code: "supporting_detail_contradiction",
|
|
327
|
-
message: "proof_sufficiency_state unavailable must be supported by allowed_proof_forms including unavailable",
|
|
214
|
+
message: "visibility_derivation.derived_from_axes must contain exactly the four canonical source-safety axes",
|
|
328
215
|
subjectId: args.row.safety_row_id,
|
|
329
|
-
axis: "proof_sufficiency_state",
|
|
330
|
-
}));
|
|
331
|
-
}
|
|
332
|
-
if (args.row.redaction_evidence.allowed_proof_forms.includes("unavailable") &&
|
|
333
|
-
args.row.proof_sufficiency_state !== "unavailable") {
|
|
334
|
-
args.violations.push(violation({
|
|
335
|
-
code: "supporting_detail_contradiction",
|
|
336
|
-
message: "allowed_proof_forms unavailable contradicts a top-level proof_sufficiency_state that is not unavailable",
|
|
337
|
-
subjectId: args.row.safety_row_id,
|
|
338
|
-
axis: "proof_sufficiency_state",
|
|
339
|
-
}));
|
|
340
|
-
}
|
|
341
|
-
if (args.row.redaction_evidence.raw_value_available === false &&
|
|
342
|
-
args.row.redaction_evidence.allowed_proof_forms.includes("raw_value")) {
|
|
343
|
-
args.violations.push(violation({
|
|
344
|
-
code: "supporting_detail_contradiction",
|
|
345
|
-
message: "redaction_evidence cannot allow raw_value when raw_value_available is false",
|
|
346
|
-
subjectId: args.row.safety_row_id,
|
|
347
|
-
axis: "redaction_state",
|
|
348
216
|
}));
|
|
349
217
|
}
|
|
350
218
|
}
|
|
@@ -354,9 +222,6 @@ function normalizeSafetyRow(rawRow) {
|
|
|
354
222
|
const derivation = isRecord(rawRow.visibility_derivation)
|
|
355
223
|
? rawRow.visibility_derivation
|
|
356
224
|
: {};
|
|
357
|
-
const redactionEvidence = isRecord(rawRow.redaction_evidence)
|
|
358
|
-
? rawRow.redaction_evidence
|
|
359
|
-
: {};
|
|
360
225
|
const tombstone = isRecord(rawRow.tombstone) ? rawRow.tombstone : {};
|
|
361
226
|
return {
|
|
362
227
|
safety_row_id: typeof rawRow.safety_row_id === "string" ? rawRow.safety_row_id : "",
|
|
@@ -370,12 +235,6 @@ function normalizeSafetyRow(rawRow) {
|
|
|
370
235
|
authorization_state: inList(rawRow.authorization_state, AUTHORIZATION_STATES)
|
|
371
236
|
? rawRow.authorization_state
|
|
372
237
|
: "",
|
|
373
|
-
privacy_state: inList(rawRow.privacy_state, PRIVACY_STATES)
|
|
374
|
-
? rawRow.privacy_state
|
|
375
|
-
: "",
|
|
376
|
-
redaction_state: inList(rawRow.redaction_state, REDACTION_STATES)
|
|
377
|
-
? rawRow.redaction_state
|
|
378
|
-
: "",
|
|
379
238
|
proof_sufficiency_state: inList(rawRow.proof_sufficiency_state, PROOF_SUFFICIENCY_STATES)
|
|
380
239
|
? rawRow.proof_sufficiency_state
|
|
381
240
|
: "",
|
|
@@ -389,7 +248,13 @@ function normalizeSafetyRow(rawRow) {
|
|
|
389
248
|
intended_consumption: inList(derivation.intended_consumption, INTENDED_CONSUMPTIONS)
|
|
390
249
|
? derivation.intended_consumption
|
|
391
250
|
: "",
|
|
392
|
-
|
|
251
|
+
// Keep every string entry as-is (do NOT filter to the canonical set): a stale
|
|
252
|
+
// or tampered row carrying retired axes (e.g. privacy_state/redaction_state)
|
|
253
|
+
// must reach validateCanonicalAxes and fail `visibility_axis_set_invalid`,
|
|
254
|
+
// not be silently laundered down to exactly the four canonical axes.
|
|
255
|
+
derived_from_axes: (Array.isArray(derivation.derived_from_axes)
|
|
256
|
+
? derivation.derived_from_axes.filter((axis) => typeof axis === "string")
|
|
257
|
+
: []),
|
|
393
258
|
derivation_rule_ref: typeof derivation.derivation_rule_ref === "string"
|
|
394
259
|
? derivation.derivation_rule_ref
|
|
395
260
|
: "",
|
|
@@ -397,13 +262,6 @@ function normalizeSafetyRow(rawRow) {
|
|
|
397
262
|
authorization_scope_ref: typeof rawRow.authorization_scope_ref === "string"
|
|
398
263
|
? rawRow.authorization_scope_ref
|
|
399
264
|
: null,
|
|
400
|
-
redaction_evidence: {
|
|
401
|
-
raw_value_available: redactionEvidence.raw_value_available === true,
|
|
402
|
-
allowed_proof_forms: arrayValues(redactionEvidence.allowed_proof_forms, ALLOWED_PROOF_FORMS),
|
|
403
|
-
redaction_rule_ref: typeof redactionEvidence.redaction_rule_ref === "string"
|
|
404
|
-
? redactionEvidence.redaction_rule_ref
|
|
405
|
-
: null,
|
|
406
|
-
},
|
|
407
265
|
tombstone: {
|
|
408
266
|
tombstone_ref: typeof tombstone.tombstone_ref === "string" ? tombstone.tombstone_ref : null,
|
|
409
267
|
reason: typeof tombstone.reason === "string" ? tombstone.reason : null,
|
|
@@ -420,6 +278,23 @@ function normalizeSafetyRow(rawRow) {
|
|
|
420
278
|
export function validateSourceSafetyLedger(args) {
|
|
421
279
|
assertArrayField(args.sourceObservations.observations, "source-observations", "observations");
|
|
422
280
|
const violations = [];
|
|
281
|
+
// G(a) deferred-7 slice 1: record the three obligations this validator fully enforces. Stamped here,
|
|
282
|
+
// before the per-row loop, so they fire on zero-row input (the enforcement sites exist unconditionally).
|
|
283
|
+
// asserted_obligation_ids is in-memory-only telemetry (Stage 0 #145): it is stripped at the write
|
|
284
|
+
// boundary and excluded from reuseMatchArtifactHash, so stamping this reuse-hashed validation artifact
|
|
285
|
+
// does not rotate reuse provenance. PARKED (see obligation-coverage-ledger.yaml):
|
|
286
|
+
// - preserve_..._consumption_boundaries: no independent "no substitution" enforcer (the per-consumption
|
|
287
|
+
// required rows are the only related check), so it cannot bind non-overlappingly.
|
|
288
|
+
// - validate_every_observation_has_source_safety_rows_for_each_intended_consumption (codex #147 P1):
|
|
289
|
+
// the required-row pass only proves each source_safety:<obs>:<consumption> ID STRING is present; it
|
|
290
|
+
// never binds that ID suffix to the row's visibility_derivation.intended_consumption (the field
|
|
291
|
+
// deriveSourceSafetyVisibilityTier uses). So a public_output-ID row can carry prompt_context
|
|
292
|
+
// derivation and a tier derived for the wrong consumption, pass, and mislead downstream lookup-by-ID.
|
|
293
|
+
// PARK pending an ID-suffix ↔ intended_consumption binding.
|
|
294
|
+
const assertedObligationIds = [];
|
|
295
|
+
assertObligation(assertedObligationIds, "validate_exactly_four_canonical_source_safety_axes");
|
|
296
|
+
assertObligation(assertedObligationIds, "validate_source_safety_subject_refs_against_observed_source_refs");
|
|
297
|
+
assertObligation(assertedObligationIds, "validate_visibility_tier_is_derived_not_independent_authority");
|
|
423
298
|
const rawLedger = args.sourceSafetyLedger;
|
|
424
299
|
if (!isRecord(rawLedger) || !Array.isArray(rawLedger.safety_rows)) {
|
|
425
300
|
violations.push(violation({
|
|
@@ -510,13 +385,6 @@ export function validateSourceSafetyLedger(args) {
|
|
|
510
385
|
allowed: AUTHORIZATION_STATES,
|
|
511
386
|
axis: "authorization_state",
|
|
512
387
|
},
|
|
513
|
-
{ field: "privacy_state", value: row.privacy_state, allowed: PRIVACY_STATES, axis: "privacy_state" },
|
|
514
|
-
{
|
|
515
|
-
field: "redaction_state",
|
|
516
|
-
value: row.redaction_state,
|
|
517
|
-
allowed: REDACTION_STATES,
|
|
518
|
-
axis: "redaction_state",
|
|
519
|
-
},
|
|
520
388
|
{
|
|
521
389
|
field: "proof_sufficiency_state",
|
|
522
390
|
value: row.proof_sufficiency_state,
|
|
@@ -543,15 +411,7 @@ export function validateSourceSafetyLedger(args) {
|
|
|
543
411
|
subjectId: row.safety_row_id,
|
|
544
412
|
}));
|
|
545
413
|
}
|
|
546
|
-
if (row.redaction_evidence.allowed_proof_forms.length === 0) {
|
|
547
|
-
violations.push(violation({
|
|
548
|
-
code: "missing_required_field",
|
|
549
|
-
message: "source safety row must name at least one allowed proof form",
|
|
550
|
-
subjectId: row.safety_row_id,
|
|
551
|
-
}));
|
|
552
|
-
}
|
|
553
414
|
validateCanonicalAxes({ row, violations });
|
|
554
|
-
validateSupportingDetailConsistency({ row, violations });
|
|
555
415
|
if (VISIBILITY_TIERS.includes(row.visibility_tier)) {
|
|
556
416
|
const expected = deriveSourceSafetyVisibilityTier(row);
|
|
557
417
|
if (row.visibility_tier !== expected) {
|
|
@@ -562,6 +422,34 @@ export function validateSourceSafetyLedger(args) {
|
|
|
562
422
|
}));
|
|
563
423
|
}
|
|
564
424
|
}
|
|
425
|
+
// Defect-3 D3 (basis-attribution enforcement): an outward consumption tier
|
|
426
|
+
// (material_claim/public_output) that actually REACHES consumption_allowed MUST
|
|
427
|
+
// be justified by a canonical basis — A (the observation is the runtime target,
|
|
428
|
+
// is_runtime_target_source) or B (explicit source self-declaration). Without
|
|
429
|
+
// this, a forged/replayed row could reach consumption_allowed on a
|
|
430
|
+
// frontier-discovered/non-target source (the four axes alone don't bind to the
|
|
431
|
+
// basis). The trigger keys on the DERIVED outcome, not a single
|
|
432
|
+
// authorization_state literal: both "authorized" AND "not_required" derive to
|
|
433
|
+
// consumption_allowed for these tiers, so checking only "authorized" left a
|
|
434
|
+
// "not_required" bypass. Internal tiers are exempt (runtime read scope), and a
|
|
435
|
+
// legit non-target row derives to no_prompt_use (producer emits "unknown"), so
|
|
436
|
+
// D3 stays silent there.
|
|
437
|
+
const consumption = row.visibility_derivation.intended_consumption;
|
|
438
|
+
if ((consumption === "material_claim" || consumption === "public_output") &&
|
|
439
|
+
deriveSourceSafetyVisibilityTier(row) === "consumption_allowed" &&
|
|
440
|
+
expectedObservation) {
|
|
441
|
+
const basisA = expectedObservation.is_runtime_target_source === true;
|
|
442
|
+
const basisB = explicitConsumptionAuthorizations(expectedObservation)
|
|
443
|
+
.has(consumption);
|
|
444
|
+
if (!basisA && !basisB) {
|
|
445
|
+
violations.push(violation({
|
|
446
|
+
code: "unjustified_consumption_authorization",
|
|
447
|
+
message: `source safety row ${row.safety_row_id} reaches consumption_allowed for ${consumption} without a runtime-target-provenance (A) or explicit-source (B) authorization basis`,
|
|
448
|
+
subjectId: row.safety_row_id,
|
|
449
|
+
axis: "authorization_state",
|
|
450
|
+
}));
|
|
451
|
+
}
|
|
452
|
+
}
|
|
565
453
|
}
|
|
566
454
|
for (const requiredSafetyRowId of requiredSafetyRowIds) {
|
|
567
455
|
if (!rowIds.has(requiredSafetyRowId)) {
|
|
@@ -583,10 +471,10 @@ export function validateSourceSafetyLedger(args) {
|
|
|
583
471
|
safety_row_count: rows.length,
|
|
584
472
|
no_prompt_use_count: rows.filter((row) => row.visibility_tier === "no_prompt_use")
|
|
585
473
|
.length,
|
|
586
|
-
redacted_output_only_count: rows.filter((row) => row.visibility_tier === "redacted_output_only").length,
|
|
587
474
|
validation_results: violations.length === 0
|
|
588
475
|
? ["source_safety_ledger_valid"]
|
|
589
476
|
: ["source_safety_ledger_invalid"],
|
|
477
|
+
asserted_obligation_ids: assertedObligationIds,
|
|
590
478
|
violations,
|
|
591
479
|
};
|
|
592
480
|
}
|
|
@@ -3,6 +3,7 @@ import fs from "node:fs/promises";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { parse as parseYaml } from "yaml";
|
|
5
5
|
import { assertArrayField, atomicWriteYamlDocument as writeYamlDocument } from "../artifact-io.js";
|
|
6
|
+
import { assertObligation } from "./obligation-assertion.js";
|
|
6
7
|
import { sourceSafetyRowIdForObservation } from "./source-safety-validation.js";
|
|
7
8
|
const SIGNAL_AXES = [
|
|
8
9
|
"actor",
|
|
@@ -172,7 +173,6 @@ function visibilityStateForSafetyRow(row) {
|
|
|
172
173
|
case "consumption_allowed":
|
|
173
174
|
return "prompt_visible";
|
|
174
175
|
case "internal_only":
|
|
175
|
-
case "redacted_output_only":
|
|
176
176
|
return "redacted";
|
|
177
177
|
case "no_prompt_use":
|
|
178
178
|
case "no_replay_use":
|
|
@@ -405,6 +405,41 @@ export async function validateSourceScoutPack(args) {
|
|
|
405
405
|
assertArrayField(args.sourceObservations.observations, "source-observations", "observations");
|
|
406
406
|
assertArrayField(args.sourceScoutPack.profile_scout_coverage_slots, "source-scout-pack", "profile_scout_coverage_slots");
|
|
407
407
|
const violations = [];
|
|
408
|
+
// G(a) deferred-7 slice 5 (LAST): ONE mode-agnostic fn is shared by THREE registry validator_ids
|
|
409
|
+
// (source-scout-pack[-pre-seed|-post-maturation]-validator) — no mode arg, one uniform check set. The harvest
|
|
410
|
+
// attributes this asserted set to ALL 3 validator_ids; recording only an obligation registered for all 3
|
|
411
|
+
// (no registry-absent pair). asserted_obligation_ids is in-memory-only telemetry (Stage 0 #145) on a
|
|
412
|
+
// reuse-hashed (run.ts source_scout_pack_validation_sha256) + scout-captured (sha256File raw-file) artifact,
|
|
413
|
+
// so stamping rotates neither channel. Stamped before the per-row loop so it fires on zero signal rows.
|
|
414
|
+
//
|
|
415
|
+
// RECORD 1 (shared across all 3 modes, uniformly enforced):
|
|
416
|
+
// - validate_signal_rows_resolve_to_source_observations → signal_observation_missing (per-row, UNCONDITIONAL:
|
|
417
|
+
// every signal row's observation_id must resolve in source-observations; +per-row content-sha match). The
|
|
418
|
+
// passed observations are bound to the chain via source_observations_hash_mismatch (pack snapshot hash vs
|
|
419
|
+
// sha256File(ref)); the resolution check itself does not depend on that pinning.
|
|
420
|
+
//
|
|
421
|
+
// PARKED 8 (ledger notes carry detail):
|
|
422
|
+
// - validate_prompt_visible_rows_have_source_safety_validation_refs (×3): the named per-row field
|
|
423
|
+
// source_safety_ledger_validation_ref is BUILT but never read by the validator — it checks source_safety_
|
|
424
|
+
// row_id (ledger row) + global validation_status + tier instead, so the named validation-ref field is
|
|
425
|
+
// unenforced (a row with valid row_id but null/wrong validation_ref passes).
|
|
426
|
+
// - validate_group_and_coverage_refs_resolve (base): "group" has no enforcement surface (no group structure);
|
|
427
|
+
// only coverage_slot→signal_row resolution (coverage_slot_signal_missing) is checked → compound, half missing.
|
|
428
|
+
// - validate_scout_pack_is_profile_local_and_contains_no_selected_purpose_required_element_refs (base):
|
|
429
|
+
// validateNoSelectedPurposeLeak is a JSON substring search (no-purpose-leak half, fragile); "profile-local"
|
|
430
|
+
// is never checked → compound, half missing.
|
|
431
|
+
// - validate_scout_scope_derives_from_target_material_profile_validation (base) /
|
|
432
|
+
// validate_snapshot_scope_derives_from_target_material_profile_validation (pre-seed+post-maturation):
|
|
433
|
+
// scout_scope is copied from the pack; only internal consistency (unsupported_scope_overclaimed) is checked,
|
|
434
|
+
// never recomputed/derived from the target-material-profile-validation content (scoutScopeState() unused here).
|
|
435
|
+
// - validate_snapshot_lineage_validation_ref_and_hash_match_current_lineage_authority (pre-seed+post-maturation):
|
|
436
|
+
// slice-3 null-read + caller-authority — sha256File(null)=null so a null lineage ref + null pack hash passes,
|
|
437
|
+
// and the "current lineage authority" is the caller-supplied ref, not derived from the chain.
|
|
438
|
+
// - validate_pre_seed_scout_snapshot_is_immutable_consumed_authority (pre-seed) /
|
|
439
|
+
// validate_post_maturation_scout_snapshot_is_immutable_audit_authority (post-maturation): only INPUT-artifact
|
|
440
|
+
// hashes (freshness) are checked; snapshot immutability / consumed-or-audit authority state is not enforced.
|
|
441
|
+
const assertedObligationIds = [];
|
|
442
|
+
assertObligation(assertedObligationIds, "validate_signal_rows_resolve_to_source_observations");
|
|
408
443
|
// signal_rows is this validator's primary subject and is already shape-checked
|
|
409
444
|
// gracefully below (→ schema_shape_invalid violation), so it is NOT asserted.
|
|
410
445
|
const rawPack = args.sourceScoutPack;
|
|
@@ -653,6 +688,7 @@ export async function validateSourceScoutPack(args) {
|
|
|
653
688
|
validation_results: violations.length === 0
|
|
654
689
|
? ["source_scout_pack_valid"]
|
|
655
690
|
: ["source_scout_pack_invalid"],
|
|
691
|
+
asserted_obligation_ids: assertedObligationIds,
|
|
656
692
|
violations,
|
|
657
693
|
};
|
|
658
694
|
}
|