@mcptoolshop/research-os 0.3.0 → 0.3.2
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/CHANGELOG.md +214 -0
- package/README.es.md +99 -71
- package/README.fr.md +86 -58
- package/README.hi.md +83 -59
- package/README.it.md +97 -73
- package/README.ja.md +86 -58
- package/README.md +8 -4
- package/README.pt-BR.md +83 -59
- package/README.zh.md +102 -74
- package/dist/cli.js +281 -62
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +174 -84
- package/dist/index.js +185 -48
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -112,7 +112,7 @@ var init_errors = __esm({
|
|
|
112
112
|
|
|
113
113
|
// src/intake/schema.ts
|
|
114
114
|
import { z } from "zod";
|
|
115
|
-
var SectionStatusSchema, SectionSchema, SourceFloorGateSchema, ClaimIntegrityGateSchema, FreshnessGateSchema, ContradictionGateSchema, SectionBudgetGateSchema, GateConfigSchema, PrimarySourceWaiverSchema, FreshnessRequirementsSchema, ReviewProfilePresetSchema, DEFAULT_REVIEW_PROFILES, ResearchYamlSchema;
|
|
115
|
+
var SectionStatusSchema, SectionSchema, SourceFloorGateSchema, ClaimIntegrityGateSchema, FreshnessGateSchema, ContradictionGateSchema, SectionBudgetGateSchema, GateConfigSchema, SectionScopedWaiverSchema, PrimarySourceWaiverSchema, FreshnessRequirementsSchema, ReviewProfilePresetSchema, DEFAULT_REVIEW_PROFILES, ResearchYamlSchema;
|
|
116
116
|
var init_schema = __esm({
|
|
117
117
|
"src/intake/schema.ts"() {
|
|
118
118
|
"use strict";
|
|
@@ -162,10 +162,20 @@ var init_schema = __esm({
|
|
|
162
162
|
contradiction: ContradictionGateSchema.default({}),
|
|
163
163
|
section_budget: SectionBudgetGateSchema.default({})
|
|
164
164
|
});
|
|
165
|
+
SectionScopedWaiverSchema = z.object({
|
|
166
|
+
section_id: z.string().regex(/^[0-9]{2}-[a-z0-9-]+$/, 'Section id must look like "01-landscape"'),
|
|
167
|
+
scope: z.enum(["min_independent_publishers", "primary_sources_required"]),
|
|
168
|
+
reason: z.string().min(1),
|
|
169
|
+
compensating_controls: z.array(z.string()).min(1)
|
|
170
|
+
});
|
|
165
171
|
PrimarySourceWaiverSchema = z.object({
|
|
166
172
|
status: z.enum(["none", "requested", "granted"]).default("none"),
|
|
167
173
|
reason: z.string().optional(),
|
|
168
|
-
compensating_controls: z.array(z.string()).default([])
|
|
174
|
+
compensating_controls: z.array(z.string()).default([]),
|
|
175
|
+
// Section-scoped waivers; each entry is its own waiver record. Independent
|
|
176
|
+
// of the pack-level status/reason/compensating_controls fields above.
|
|
177
|
+
// Defaults to [] for backward compatibility — existing packs unaffected.
|
|
178
|
+
section_waivers: z.array(SectionScopedWaiverSchema).default([])
|
|
169
179
|
});
|
|
170
180
|
FreshnessRequirementsSchema = z.object({
|
|
171
181
|
required: z.boolean().default(true),
|
|
@@ -4222,9 +4232,28 @@ function applyWaivers(input, results) {
|
|
|
4222
4232
|
const updated = results.map((r) => ({ ...r }));
|
|
4223
4233
|
const applied = [];
|
|
4224
4234
|
const validationFailures = [];
|
|
4225
|
-
|
|
4226
|
-
|
|
4235
|
+
applyPackLevelWaiver({
|
|
4236
|
+
waiver,
|
|
4237
|
+
cfg,
|
|
4238
|
+
updated,
|
|
4239
|
+
applied,
|
|
4240
|
+
validationFailures
|
|
4241
|
+
});
|
|
4242
|
+
for (const sw of waiver.section_waivers ?? []) {
|
|
4243
|
+
if (sw.section_id !== input.section.id) continue;
|
|
4244
|
+
applySectionScopedWaiver({
|
|
4245
|
+
waiver: sw,
|
|
4246
|
+
cfg,
|
|
4247
|
+
updated,
|
|
4248
|
+
applied,
|
|
4249
|
+
validationFailures
|
|
4250
|
+
});
|
|
4227
4251
|
}
|
|
4252
|
+
return { updatedResults: updated, waivers_applied: applied, waiver_validation_failures: validationFailures };
|
|
4253
|
+
}
|
|
4254
|
+
function applyPackLevelWaiver(args) {
|
|
4255
|
+
const { waiver, cfg, updated, applied, validationFailures } = args;
|
|
4256
|
+
if (waiver.status !== "granted") return;
|
|
4228
4257
|
if (!waiver.reason || waiver.reason.trim().length === 0) {
|
|
4229
4258
|
validationFailures.push({
|
|
4230
4259
|
family: "waivers",
|
|
@@ -4234,7 +4263,7 @@ function applyWaivers(input, results) {
|
|
|
4234
4263
|
evidence: [],
|
|
4235
4264
|
blocks_synthesis: true
|
|
4236
4265
|
});
|
|
4237
|
-
return
|
|
4266
|
+
return;
|
|
4238
4267
|
}
|
|
4239
4268
|
if (waiver.compensating_controls.length === 0) {
|
|
4240
4269
|
validationFailures.push({
|
|
@@ -4245,7 +4274,7 @@ function applyWaivers(input, results) {
|
|
|
4245
4274
|
evidence: [],
|
|
4246
4275
|
blocks_synthesis: true
|
|
4247
4276
|
});
|
|
4248
|
-
return
|
|
4277
|
+
return;
|
|
4249
4278
|
}
|
|
4250
4279
|
if (!cfg.primary_source_waiver_allowed) {
|
|
4251
4280
|
validationFailures.push({
|
|
@@ -4256,7 +4285,7 @@ function applyWaivers(input, results) {
|
|
|
4256
4285
|
evidence: [],
|
|
4257
4286
|
blocks_synthesis: true
|
|
4258
4287
|
});
|
|
4259
|
-
return
|
|
4288
|
+
return;
|
|
4260
4289
|
}
|
|
4261
4290
|
for (let i = 0; i < updated.length; i += 1) {
|
|
4262
4291
|
const r = updated[i];
|
|
@@ -4278,7 +4307,62 @@ function applyWaivers(input, results) {
|
|
|
4278
4307
|
});
|
|
4279
4308
|
}
|
|
4280
4309
|
}
|
|
4281
|
-
|
|
4310
|
+
}
|
|
4311
|
+
function applySectionScopedWaiver(args) {
|
|
4312
|
+
const { waiver, cfg, updated, applied, validationFailures } = args;
|
|
4313
|
+
if (!waiver.reason || waiver.reason.trim().length === 0) {
|
|
4314
|
+
validationFailures.push({
|
|
4315
|
+
family: "waivers",
|
|
4316
|
+
check: "section_scoped_waiver_reason_required",
|
|
4317
|
+
status: "fail",
|
|
4318
|
+
detail: `Section-scoped waiver for ${waiver.section_id}/${waiver.scope} is missing a reason. Waiver is invalid; original failure stands.`,
|
|
4319
|
+
evidence: [waiver.section_id],
|
|
4320
|
+
blocks_synthesis: true
|
|
4321
|
+
});
|
|
4322
|
+
return;
|
|
4323
|
+
}
|
|
4324
|
+
if (waiver.compensating_controls.length === 0) {
|
|
4325
|
+
validationFailures.push({
|
|
4326
|
+
family: "waivers",
|
|
4327
|
+
check: "section_scoped_waiver_compensating_controls_required",
|
|
4328
|
+
status: "fail",
|
|
4329
|
+
detail: `Section-scoped waiver for ${waiver.section_id}/${waiver.scope} has empty compensating_controls. Waiver is invalid; original failure stands.`,
|
|
4330
|
+
evidence: [waiver.section_id],
|
|
4331
|
+
blocks_synthesis: true
|
|
4332
|
+
});
|
|
4333
|
+
return;
|
|
4334
|
+
}
|
|
4335
|
+
if (!cfg.primary_source_waiver_allowed) {
|
|
4336
|
+
validationFailures.push({
|
|
4337
|
+
family: "waivers",
|
|
4338
|
+
check: "section_scoped_waiver_allowed_by_pack",
|
|
4339
|
+
status: "fail",
|
|
4340
|
+
detail: `Pack policy gates.source_floor.primary_source_waiver_allowed=false; section-scoped waiver for ${waiver.section_id}/${waiver.scope} cannot be applied.`,
|
|
4341
|
+
evidence: [waiver.section_id],
|
|
4342
|
+
blocks_synthesis: true
|
|
4343
|
+
});
|
|
4344
|
+
return;
|
|
4345
|
+
}
|
|
4346
|
+
for (let i = 0; i < updated.length; i += 1) {
|
|
4347
|
+
const r = updated[i];
|
|
4348
|
+
if (r.family === "source_floor" && r.check === waiver.scope && r.status === "fail") {
|
|
4349
|
+
const original = r.status;
|
|
4350
|
+
updated[i] = {
|
|
4351
|
+
...r,
|
|
4352
|
+
status: "pass_with_waiver",
|
|
4353
|
+
detail: `${r.detail} Section-scoped waiver granted for ${waiver.section_id} with ${waiver.compensating_controls.length} compensating control(s); converted from fail to pass_with_waiver.`,
|
|
4354
|
+
blocks_synthesis: false
|
|
4355
|
+
};
|
|
4356
|
+
applied.push({
|
|
4357
|
+
family: "source_floor",
|
|
4358
|
+
check: waiver.scope,
|
|
4359
|
+
reason: waiver.reason,
|
|
4360
|
+
compensating_controls: waiver.compensating_controls,
|
|
4361
|
+
original_status: original,
|
|
4362
|
+
new_status: "pass_with_waiver"
|
|
4363
|
+
});
|
|
4364
|
+
}
|
|
4365
|
+
}
|
|
4282
4366
|
}
|
|
4283
4367
|
var init_waivers = __esm({
|
|
4284
4368
|
"src/gates/checks/waivers.ts"() {
|
|
@@ -5535,9 +5619,11 @@ function pickHighestPriority(decisions) {
|
|
|
5535
5619
|
return "accepted_for_synthesis";
|
|
5536
5620
|
}
|
|
5537
5621
|
function deriveClaimReviews(args) {
|
|
5538
|
-
const { claims, findings, reviewer, reviewMethod } = args;
|
|
5622
|
+
const { claims, findings, reviewer, reviewMethod, activeSectionWaivers } = args;
|
|
5539
5623
|
const reviews = [];
|
|
5540
5624
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
5625
|
+
const monopolyWaived = Array.isArray(activeSectionWaivers) && activeSectionWaivers.some((w) => w.scope === "min_independent_publishers");
|
|
5626
|
+
const isWaivedFinding = (f) => monopolyWaived && f.category === "source_cluster_monopoly";
|
|
5541
5627
|
for (const claim of claims) {
|
|
5542
5628
|
const claimFindings = findings.filter((f) => f.claim_ids.includes(claim.claim_id));
|
|
5543
5629
|
if (claimFindings.length === 0) {
|
|
@@ -5554,6 +5640,7 @@ function deriveClaimReviews(args) {
|
|
|
5554
5640
|
}
|
|
5555
5641
|
let decisions = [];
|
|
5556
5642
|
for (const f of claimFindings) {
|
|
5643
|
+
if (isWaivedFinding(f)) continue;
|
|
5557
5644
|
if (f.severity === "block") {
|
|
5558
5645
|
decisions.push(BLOCK_TO_DECISION[f.category] ?? "rejected");
|
|
5559
5646
|
} else if (f.severity === "warn") {
|
|
@@ -5570,7 +5657,9 @@ function deriveClaimReviews(args) {
|
|
|
5570
5657
|
);
|
|
5571
5658
|
}
|
|
5572
5659
|
const decision = pickHighestPriority(decisions);
|
|
5573
|
-
const reasonParts = claimFindings.filter((f) => f.severity !== "info").map(
|
|
5660
|
+
const reasonParts = claimFindings.filter((f) => f.severity !== "info").map(
|
|
5661
|
+
(f) => isWaivedFinding(f) ? `${f.category} (${f.severity}, waived)` : `${f.category} (${f.severity})`
|
|
5662
|
+
);
|
|
5574
5663
|
const reason = reasonParts.length > 0 ? `Findings: ${reasonParts.join("; ")}.` : "Only info-level findings; accepted.";
|
|
5575
5664
|
reviews.push({
|
|
5576
5665
|
claim_id: claim.claim_id,
|
|
@@ -5951,7 +6040,8 @@ async function review(options) {
|
|
|
5951
6040
|
candidateClaims,
|
|
5952
6041
|
drafts: acceptedDrafts,
|
|
5953
6042
|
llmFindingsRejected,
|
|
5954
|
-
profile: options.profile ?? DEFAULT_PROFILE
|
|
6043
|
+
profile: options.profile ?? DEFAULT_PROFILE,
|
|
6044
|
+
research
|
|
5955
6045
|
});
|
|
5956
6046
|
}
|
|
5957
6047
|
async function runMultiPassReview(args) {
|
|
@@ -6013,7 +6103,8 @@ async function runMultiPassReview(args) {
|
|
|
6013
6103
|
candidateClaims: args.candidateClaims,
|
|
6014
6104
|
drafts: merged,
|
|
6015
6105
|
llmFindingsRejected,
|
|
6016
|
-
profile: args.options.profile ?? DEFAULT_PROFILE
|
|
6106
|
+
profile: args.options.profile ?? DEFAULT_PROFILE,
|
|
6107
|
+
research: args.research
|
|
6017
6108
|
});
|
|
6018
6109
|
}
|
|
6019
6110
|
async function reviewWithSpecificReviewer(args) {
|
|
@@ -6041,7 +6132,8 @@ async function reviewWithSpecificReviewer(args) {
|
|
|
6041
6132
|
candidateClaims: args.candidateClaims,
|
|
6042
6133
|
drafts: result.drafts,
|
|
6043
6134
|
llmFindingsRejected: 0,
|
|
6044
|
-
profile: args.options.profile ?? DEFAULT_PROFILE
|
|
6135
|
+
profile: args.options.profile ?? DEFAULT_PROFILE,
|
|
6136
|
+
research: args.research
|
|
6045
6137
|
});
|
|
6046
6138
|
}
|
|
6047
6139
|
async function finalizeReview(args) {
|
|
@@ -6064,11 +6156,15 @@ async function finalizeReview(args) {
|
|
|
6064
6156
|
seen.add(f.finding_id);
|
|
6065
6157
|
dedupedFindings.push(f);
|
|
6066
6158
|
}
|
|
6159
|
+
const activeSectionWaivers = args.research.primary_source_waiver.section_waivers.filter(
|
|
6160
|
+
(w) => w.section_id === args.sectionId
|
|
6161
|
+
);
|
|
6067
6162
|
const claimReviews = deriveClaimReviews({
|
|
6068
6163
|
claims: args.candidateClaims,
|
|
6069
6164
|
findings: dedupedFindings,
|
|
6070
6165
|
reviewer: args.reviewer,
|
|
6071
|
-
reviewMethod: args.reviewMethod
|
|
6166
|
+
reviewMethod: args.reviewMethod,
|
|
6167
|
+
activeSectionWaivers
|
|
6072
6168
|
});
|
|
6073
6169
|
const decisionCounts = {
|
|
6074
6170
|
accepted_for_synthesis: 0,
|
|
@@ -8795,6 +8891,19 @@ function buildStaleSources(input) {
|
|
|
8795
8891
|
}
|
|
8796
8892
|
return out;
|
|
8797
8893
|
}
|
|
8894
|
+
function findSectionWaiver(research, sectionId, scope) {
|
|
8895
|
+
return (research.primary_source_waiver.section_waivers ?? []).find(
|
|
8896
|
+
(w) => w.section_id === sectionId && w.scope === scope
|
|
8897
|
+
);
|
|
8898
|
+
}
|
|
8899
|
+
function annotateWeakSource(row, waiver) {
|
|
8900
|
+
if (!waiver) return row;
|
|
8901
|
+
return { ...row, waived: true, waiver_reason: waiver.reason };
|
|
8902
|
+
}
|
|
8903
|
+
function annotateDiversityGap(row, waiver) {
|
|
8904
|
+
if (!waiver) return row;
|
|
8905
|
+
return { ...row, waived: true, waiver_reason: waiver.reason };
|
|
8906
|
+
}
|
|
8798
8907
|
function buildWeakSources(input) {
|
|
8799
8908
|
const out = [];
|
|
8800
8909
|
const cfg = input.research.gates.source_floor;
|
|
@@ -8804,33 +8913,50 @@ function buildWeakSources(input) {
|
|
|
8804
8913
|
const publishers = new Set(
|
|
8805
8914
|
sectionSources.map((c) => c.publisher).filter((p) => typeof p === "string")
|
|
8806
8915
|
);
|
|
8916
|
+
const monopolyWaiver = findSectionWaiver(input.research, sid, "min_independent_publishers");
|
|
8917
|
+
const primaryWaiver = findSectionWaiver(input.research, sid, "primary_sources_required");
|
|
8807
8918
|
if (publishers.size === 1 && sectionSources.length >= 2) {
|
|
8808
|
-
out.push(
|
|
8809
|
-
|
|
8810
|
-
|
|
8811
|
-
|
|
8812
|
-
|
|
8813
|
-
|
|
8814
|
-
|
|
8919
|
+
out.push(
|
|
8920
|
+
annotateWeakSource(
|
|
8921
|
+
{
|
|
8922
|
+
reason: "source_cluster_monopoly",
|
|
8923
|
+
section_id: sid,
|
|
8924
|
+
details: `Every source in this section traces to a single publisher (${[...publishers][0]}).`,
|
|
8925
|
+
evidence_ids: sectionSources.map((s) => s.source_id),
|
|
8926
|
+
artifact_path: `sections/${sid}/sources.jsonl`
|
|
8927
|
+
},
|
|
8928
|
+
monopolyWaiver
|
|
8929
|
+
)
|
|
8930
|
+
);
|
|
8815
8931
|
}
|
|
8816
8932
|
if (publishers.size < cfg.min_independent_publishers) {
|
|
8817
|
-
out.push(
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
|
|
8933
|
+
out.push(
|
|
8934
|
+
annotateWeakSource(
|
|
8935
|
+
{
|
|
8936
|
+
reason: "low_independent_publishers",
|
|
8937
|
+
section_id: sid,
|
|
8938
|
+
details: `${publishers.size} independent publisher(s) \u2014 pack policy requires at least ${cfg.min_independent_publishers}.`,
|
|
8939
|
+
evidence_ids: [...publishers],
|
|
8940
|
+
artifact_path: `sections/${sid}/sources.jsonl`
|
|
8941
|
+
},
|
|
8942
|
+
monopolyWaiver
|
|
8943
|
+
)
|
|
8944
|
+
);
|
|
8824
8945
|
}
|
|
8825
8946
|
const primary = sectionSources.filter((c) => c.source_type === "primary").length;
|
|
8826
8947
|
if (primary < cfg.primary_sources_required) {
|
|
8827
|
-
out.push(
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
8831
|
-
|
|
8832
|
-
|
|
8833
|
-
|
|
8948
|
+
out.push(
|
|
8949
|
+
annotateWeakSource(
|
|
8950
|
+
{
|
|
8951
|
+
reason: "missing_primary_source",
|
|
8952
|
+
section_id: sid,
|
|
8953
|
+
details: `${primary} primary source(s) \u2014 pack policy requires at least ${cfg.primary_sources_required}.`,
|
|
8954
|
+
evidence_ids: sectionSources.filter((c) => c.source_type === "primary").map((c) => c.source_id),
|
|
8955
|
+
artifact_path: `sections/${sid}/sources.jsonl`
|
|
8956
|
+
},
|
|
8957
|
+
primaryWaiver
|
|
8958
|
+
)
|
|
8959
|
+
);
|
|
8834
8960
|
}
|
|
8835
8961
|
const types = /* @__PURE__ */ new Map();
|
|
8836
8962
|
for (const c of sectionSources) types.set(c.source_type, (types.get(c.source_type) ?? 0) + 1);
|
|
@@ -8945,20 +9071,31 @@ function buildSourceDiversityGaps(input) {
|
|
|
8945
9071
|
});
|
|
8946
9072
|
continue;
|
|
8947
9073
|
}
|
|
9074
|
+
const monopolyWaiver = findSectionWaiver(input.research, sid, "min_independent_publishers");
|
|
8948
9075
|
if (publishers.size === 1 && sectionSources.length >= 2) {
|
|
8949
|
-
out.push(
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
|
|
8953
|
-
|
|
8954
|
-
|
|
9076
|
+
out.push(
|
|
9077
|
+
annotateDiversityGap(
|
|
9078
|
+
{
|
|
9079
|
+
reason: "section_publisher_monopoly",
|
|
9080
|
+
section_id: sid,
|
|
9081
|
+
details: `Section sources monopolized by ${[...publishers][0]}.`,
|
|
9082
|
+
evidence_ids: sectionSources.map((s) => s.source_id)
|
|
9083
|
+
},
|
|
9084
|
+
monopolyWaiver
|
|
9085
|
+
)
|
|
9086
|
+
);
|
|
8955
9087
|
} else if (publishers.size < cfg.min_independent_publishers) {
|
|
8956
|
-
out.push(
|
|
8957
|
-
|
|
8958
|
-
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
|
|
9088
|
+
out.push(
|
|
9089
|
+
annotateDiversityGap(
|
|
9090
|
+
{
|
|
9091
|
+
reason: "low_section_publisher_count",
|
|
9092
|
+
section_id: sid,
|
|
9093
|
+
details: `${publishers.size} publisher(s); pack policy requires ${cfg.min_independent_publishers}.`,
|
|
9094
|
+
evidence_ids: [...publishers]
|
|
9095
|
+
},
|
|
9096
|
+
monopolyWaiver
|
|
9097
|
+
)
|
|
9098
|
+
);
|
|
8962
9099
|
}
|
|
8963
9100
|
}
|
|
8964
9101
|
const pubSectionCount = /* @__PURE__ */ new Map();
|
|
@@ -12165,7 +12302,7 @@ var init_src = __esm({
|
|
|
12165
12302
|
init_triage();
|
|
12166
12303
|
init_discover();
|
|
12167
12304
|
init_errors();
|
|
12168
|
-
RESEARCH_OS_VERSION = "0.3.
|
|
12305
|
+
RESEARCH_OS_VERSION = "0.3.2";
|
|
12169
12306
|
}
|
|
12170
12307
|
});
|
|
12171
12308
|
init_src();
|