majlis 0.9.0 → 0.9.1
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/cli.js +271 -34
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -416,6 +416,31 @@ var init_migrations = __esm({
|
|
|
416
416
|
ALTER TABLE experiments ADD COLUMN hypothesis_file TEXT;
|
|
417
417
|
ALTER TABLE experiments ADD COLUMN provenance TEXT DEFAULT 'cycle'
|
|
418
418
|
CHECK(provenance IN ('cycle', 'catch-up', 'absorb'));
|
|
419
|
+
`);
|
|
420
|
+
},
|
|
421
|
+
// Migration 009: v8 → v9 — Chain invalidation, objective history, audit proposals
|
|
422
|
+
(db) => {
|
|
423
|
+
db.exec(`
|
|
424
|
+
ALTER TABLE experiments ADD COLUMN chain_weakened_by TEXT;
|
|
425
|
+
|
|
426
|
+
CREATE TABLE objective_history (
|
|
427
|
+
id INTEGER PRIMARY KEY,
|
|
428
|
+
objective_text TEXT NOT NULL,
|
|
429
|
+
previous_text TEXT,
|
|
430
|
+
reason TEXT NOT NULL,
|
|
431
|
+
source TEXT NOT NULL DEFAULT 'manual' CHECK(source IN ('manual', 'audit')),
|
|
432
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
433
|
+
);
|
|
434
|
+
|
|
435
|
+
CREATE TABLE audit_proposals (
|
|
436
|
+
id INTEGER PRIMARY KEY,
|
|
437
|
+
proposed_objective TEXT NOT NULL,
|
|
438
|
+
reason TEXT NOT NULL,
|
|
439
|
+
audit_output TEXT,
|
|
440
|
+
status TEXT NOT NULL DEFAULT 'pending' CHECK(status IN ('pending', 'accepted', 'rejected')),
|
|
441
|
+
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
442
|
+
resolved_at DATETIME
|
|
443
|
+
);
|
|
419
444
|
`);
|
|
420
445
|
}
|
|
421
446
|
];
|
|
@@ -1706,46 +1731,31 @@ See \`docs/workflow.md\` for the full cycle. See \`.claude/agents/\` for role de
|
|
|
1706
1731
|
|
|
1707
1732
|
### Session Discipline
|
|
1708
1733
|
- One intent per session. Declare it with \`majlis session start "intent"\`.
|
|
1709
|
-
- Stray thoughts \u2192
|
|
1734
|
+
- Stray thoughts \u2192 \`docs/inbox/\`.
|
|
1710
1735
|
- Every session ends with \`majlis session end\`.
|
|
1711
1736
|
|
|
1712
1737
|
### Before Building
|
|
1713
1738
|
- Read \`docs/synthesis/current.md\` for compressed project state.
|
|
1714
1739
|
- Run \`majlis dead-ends --sub-type <relevant>\` for structural constraints.
|
|
1715
1740
|
- Run \`majlis decisions --level judgment\` for provisional decisions to challenge.
|
|
1741
|
+
- Run \`majlis brief\` for a context dump of the current experiment state.
|
|
1716
1742
|
|
|
1717
|
-
###
|
|
1718
|
-
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
Run \`majlis status\` for live experiment state and cycle position.
|
|
1722
|
-
`;
|
|
1723
|
-
function claudeMdContent(name, objective) {
|
|
1724
|
-
return `# ${name}
|
|
1725
|
-
|
|
1726
|
-
${objective ? `**Objective:** ${objective}
|
|
1727
|
-
` : ""}## Majlis Protocol
|
|
1743
|
+
### Capturing Observations
|
|
1744
|
+
- \`majlis note "text" --tag hypothesis\` \u2014 save observations to the DB (injected into agent contexts).
|
|
1745
|
+
- \`majlis journal "text"\` \u2014 timestamped breadcrumbs during manual hacking.
|
|
1746
|
+
- \`majlis catch-up "description" --diff HEAD~3..HEAD\` \u2014 create experiment retroactively from manual work.
|
|
1728
1747
|
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
### Evidence Hierarchy (tag every decision)
|
|
1733
|
-
1. **Proof** \u2014 mathematical proof. Overturn requires error in proof.
|
|
1734
|
-
2. **Test** \u2014 empirical test. Overturn requires showing test insufficiency.
|
|
1735
|
-
3a. **Strong Consensus** \u2014 convergence across independent approaches.
|
|
1736
|
-
3b. **Consensus** \u2014 agreement from same-model experiments.
|
|
1737
|
-
4. **Analogy** \u2014 justified by similarity to prior work.
|
|
1738
|
-
5. **Judgment** \u2014 independent reasoning without precedent.
|
|
1748
|
+
### Chain Integrity
|
|
1749
|
+
- If an experiment you depend on is dead-ended, your experiment is flagged as "weakened chain".
|
|
1750
|
+
- Run \`majlis status\` to see chain warnings. Revert or proceed at your own risk.
|
|
1739
1751
|
|
|
1740
|
-
###
|
|
1741
|
-
-
|
|
1742
|
-
-
|
|
1743
|
-
- Every session ends with \`majlis session end\`.
|
|
1752
|
+
### Verification Review
|
|
1753
|
+
- If \`require_human_verify\` is enabled, experiments pause at \`verified\` for human review.
|
|
1754
|
+
- Run \`majlis resolve\` to proceed or \`majlis resolve --reject\` to dead-end.
|
|
1744
1755
|
|
|
1745
|
-
###
|
|
1746
|
-
-
|
|
1747
|
-
-
|
|
1748
|
-
- Run \`majlis decisions --level judgment\` for provisional decisions to challenge.
|
|
1756
|
+
### Purpose Audit
|
|
1757
|
+
- Circuit breaker trips (3+ failures on a sub-type) trigger a Maqasid Check.
|
|
1758
|
+
- If the audit proposes an objective rewrite, run \`majlis audit --accept\` or \`--reject\`.
|
|
1749
1759
|
|
|
1750
1760
|
### Compression Trigger
|
|
1751
1761
|
- Run \`majlis status\` \u2014 it will warn when compression is due.
|
|
@@ -1753,6 +1763,11 @@ See \`docs/workflow.md\` for the full cycle. See \`.claude/agents/\` for role de
|
|
|
1753
1763
|
### Current State
|
|
1754
1764
|
Run \`majlis status\` for live experiment state and cycle position.
|
|
1755
1765
|
`;
|
|
1766
|
+
function claudeMdContent(name, objective) {
|
|
1767
|
+
return `# ${name}
|
|
1768
|
+
|
|
1769
|
+
${objective ? `**Objective:** ${objective}
|
|
1770
|
+
` : ""}${CLAUDE_MD_SECTION2}`;
|
|
1756
1771
|
}
|
|
1757
1772
|
var DEFAULT_CONFIG3 = {
|
|
1758
1773
|
project: {
|
|
@@ -2745,7 +2760,8 @@ var init_config = __esm({
|
|
|
2745
2760
|
circuit_breaker_threshold: 3,
|
|
2746
2761
|
require_doubt_before_verify: true,
|
|
2747
2762
|
require_challenge_before_verify: false,
|
|
2748
|
-
auto_baseline_on_new_experiment: true
|
|
2763
|
+
auto_baseline_on_new_experiment: true,
|
|
2764
|
+
require_human_verify: false
|
|
2749
2765
|
},
|
|
2750
2766
|
models: {}
|
|
2751
2767
|
};
|
|
@@ -3682,7 +3698,7 @@ ${cmd.body}
|
|
|
3682
3698
|
const existing = fs8.readFileSync(claudeMdPath, "utf-8");
|
|
3683
3699
|
if (existing.includes("## Majlis Protocol")) {
|
|
3684
3700
|
const replaced = existing.replace(
|
|
3685
|
-
/## Majlis Protocol[\s\S]*?(?=\n##
|
|
3701
|
+
/## Majlis Protocol[\s\S]*?(?=\n## (?!#)(?!Majlis Protocol)|$)/,
|
|
3686
3702
|
import_shared.CLAUDE_MD_SECTION.trim()
|
|
3687
3703
|
);
|
|
3688
3704
|
if (replaced !== existing) {
|
|
@@ -3779,6 +3795,36 @@ function clearGateRejection(db, experimentId) {
|
|
|
3779
3795
|
UPDATE experiments SET gate_rejection_reason = NULL, updated_at = CURRENT_TIMESTAMP WHERE id = ?
|
|
3780
3796
|
`).run(experimentId);
|
|
3781
3797
|
}
|
|
3798
|
+
function findDependents(db, slug) {
|
|
3799
|
+
const dependents = [];
|
|
3800
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3801
|
+
const queue = [slug];
|
|
3802
|
+
while (queue.length > 0) {
|
|
3803
|
+
const current = queue.shift();
|
|
3804
|
+
if (visited.has(current)) continue;
|
|
3805
|
+
visited.add(current);
|
|
3806
|
+
const rows = db.prepare(
|
|
3807
|
+
`SELECT * FROM experiments WHERE depends_on = ? AND status NOT IN ('merged', 'dead_end')`
|
|
3808
|
+
).all(current);
|
|
3809
|
+
for (const row of rows) {
|
|
3810
|
+
dependents.push(row);
|
|
3811
|
+
queue.push(row.slug);
|
|
3812
|
+
}
|
|
3813
|
+
}
|
|
3814
|
+
return dependents;
|
|
3815
|
+
}
|
|
3816
|
+
function setChainWeakened(db, experimentId, slug) {
|
|
3817
|
+
db.prepare(`
|
|
3818
|
+
UPDATE experiments SET chain_weakened_by = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?
|
|
3819
|
+
`).run(slug, experimentId);
|
|
3820
|
+
}
|
|
3821
|
+
function cascadeChainInvalidation(db, slug) {
|
|
3822
|
+
const dependents = findDependents(db, slug);
|
|
3823
|
+
for (const dep of dependents) {
|
|
3824
|
+
setChainWeakened(db, dep.id, slug);
|
|
3825
|
+
}
|
|
3826
|
+
return dependents.length;
|
|
3827
|
+
}
|
|
3782
3828
|
function insertDecision(db, experimentId, description, evidenceLevel, justification) {
|
|
3783
3829
|
const stmt = db.prepare(`
|
|
3784
3830
|
INSERT INTO decisions (experiment_id, description, evidence_level, justification)
|
|
@@ -4057,6 +4103,28 @@ function storeHypothesisFile(db, experimentId, filePath) {
|
|
|
4057
4103
|
UPDATE experiments SET hypothesis_file = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?
|
|
4058
4104
|
`).run(filePath, experimentId);
|
|
4059
4105
|
}
|
|
4106
|
+
function insertObjectiveHistory(db, objectiveText, previousText, reason, source) {
|
|
4107
|
+
db.prepare(`
|
|
4108
|
+
INSERT INTO objective_history (objective_text, previous_text, reason, source)
|
|
4109
|
+
VALUES (?, ?, ?, ?)
|
|
4110
|
+
`).run(objectiveText, previousText, reason, source);
|
|
4111
|
+
}
|
|
4112
|
+
function insertAuditProposal(db, proposedObjective, reason, auditOutput) {
|
|
4113
|
+
db.prepare(`
|
|
4114
|
+
INSERT INTO audit_proposals (proposed_objective, reason, audit_output)
|
|
4115
|
+
VALUES (?, ?, ?)
|
|
4116
|
+
`).run(proposedObjective, reason, auditOutput);
|
|
4117
|
+
}
|
|
4118
|
+
function getPendingAuditProposal(db) {
|
|
4119
|
+
return db.prepare(
|
|
4120
|
+
`SELECT * FROM audit_proposals WHERE status = 'pending' ORDER BY created_at DESC LIMIT 1`
|
|
4121
|
+
).get();
|
|
4122
|
+
}
|
|
4123
|
+
function resolveAuditProposal(db, id, status2) {
|
|
4124
|
+
db.prepare(`
|
|
4125
|
+
UPDATE audit_proposals SET status = ?, resolved_at = CURRENT_TIMESTAMP WHERE id = ?
|
|
4126
|
+
`).run(status2, id);
|
|
4127
|
+
}
|
|
4060
4128
|
function exportForCompressor(db, maxLength = 5e4) {
|
|
4061
4129
|
const experiments = listAllExperiments(db);
|
|
4062
4130
|
const sections = ["# Structured Data Export (from SQLite)\n"];
|
|
@@ -4390,6 +4458,32 @@ async function status(isJson) {
|
|
|
4390
4458
|
]);
|
|
4391
4459
|
console.log(table(["Sub-Type", "Failures", "Status"], cbRows));
|
|
4392
4460
|
}
|
|
4461
|
+
const weakenedExps = experiments.filter((e) => e.chain_weakened_by);
|
|
4462
|
+
if (weakenedExps.length > 0) {
|
|
4463
|
+
console.log();
|
|
4464
|
+
for (const e of weakenedExps) {
|
|
4465
|
+
warn(`${e.slug} depends on ${e.chain_weakened_by} (dead-ended)`);
|
|
4466
|
+
}
|
|
4467
|
+
console.log(` Use \`majlis revert <slug>\` to abandon, or proceed at your own risk.`);
|
|
4468
|
+
}
|
|
4469
|
+
if (config.cycle.require_human_verify) {
|
|
4470
|
+
const verifiedExps = experiments.filter((e) => e.status === "verified");
|
|
4471
|
+
for (const e of verifiedExps) {
|
|
4472
|
+
const grades = getVerificationsByExperiment(db, e.id);
|
|
4473
|
+
console.log(`
|
|
4474
|
+
${bold(e.slug)}: awaiting human review (verified)`);
|
|
4475
|
+
for (const g of grades) {
|
|
4476
|
+
console.log(` ${g.component}: ${gradeColor(g.grade)}${g.notes ? ` \u2014 ${g.notes}` : ""}`);
|
|
4477
|
+
}
|
|
4478
|
+
console.log(` Run \`majlis resolve\` or \`majlis resolve --reject\``);
|
|
4479
|
+
}
|
|
4480
|
+
}
|
|
4481
|
+
const pendingProposal = getPendingAuditProposal(db);
|
|
4482
|
+
if (pendingProposal) {
|
|
4483
|
+
console.log();
|
|
4484
|
+
warn(`Pending objective rewrite: "${pendingProposal.proposed_objective}"`);
|
|
4485
|
+
console.log(` Run \`majlis audit --accept\` or \`majlis audit --reject\``);
|
|
4486
|
+
}
|
|
4393
4487
|
if (judgmentDecisions.length > 0) {
|
|
4394
4488
|
console.log(`
|
|
4395
4489
|
${yellow(`${judgmentDecisions.length} judgment-level decisions`)} (provisional targets for doubt)`);
|
|
@@ -4479,7 +4573,8 @@ var init_types2 = __esm({
|
|
|
4479
4573
|
revert: (current, target) => target === "dead_end" /* DEAD_END */ && !isTerminalStatus(current),
|
|
4480
4574
|
circuit_breaker: (current, target) => target === "dead_end" /* DEAD_END */ && !isTerminalStatus(current),
|
|
4481
4575
|
error_recovery: (current, target) => target === "dead_end" /* DEAD_END */ && !isTerminalStatus(current),
|
|
4482
|
-
bootstrap: (current, target) => current === "classified" /* CLASSIFIED */ && target === "reframed" /* REFRAMED */ || current === "classified" /* CLASSIFIED */ && target === "built" /* BUILT
|
|
4576
|
+
bootstrap: (current, target) => current === "classified" /* CLASSIFIED */ && target === "reframed" /* REFRAMED */ || current === "classified" /* CLASSIFIED */ && target === "built" /* BUILT */,
|
|
4577
|
+
objective_reset: (current, target) => target === "classified" /* CLASSIFIED */ && !isTerminalStatus(current)
|
|
4483
4578
|
};
|
|
4484
4579
|
}
|
|
4485
4580
|
});
|
|
@@ -4818,6 +4913,8 @@ async function resolve2(db, exp, projectRoot) {
|
|
|
4818
4913
|
incrementSubTypeFailure(db, exp.sub_type, exp.id, "rejected");
|
|
4819
4914
|
}
|
|
4820
4915
|
})();
|
|
4916
|
+
const weakened = cascadeChainInvalidation(db, exp.slug);
|
|
4917
|
+
if (weakened > 0) warn(`Weakened chain: ${weakened} downstream experiment(s) depend on ${exp.slug}.`);
|
|
4821
4918
|
info(`Experiment ${exp.slug} DEAD-ENDED (rejected). Constraint recorded.`);
|
|
4822
4919
|
break;
|
|
4823
4920
|
}
|
|
@@ -4954,6 +5051,8 @@ async function resolveDbOnly(db, exp, projectRoot) {
|
|
|
4954
5051
|
incrementSubTypeFailure(db, exp.sub_type, exp.id, "rejected");
|
|
4955
5052
|
}
|
|
4956
5053
|
})();
|
|
5054
|
+
const weakened = cascadeChainInvalidation(db, exp.slug);
|
|
5055
|
+
if (weakened > 0) warn(`Weakened chain: ${weakened} downstream experiment(s) depend on ${exp.slug}.`);
|
|
4957
5056
|
info(`Experiment ${exp.slug} DEAD-ENDED (rejected). Constraint recorded.`);
|
|
4958
5057
|
break;
|
|
4959
5058
|
}
|
|
@@ -5079,6 +5178,31 @@ async function resolveCmd(args) {
|
|
|
5079
5178
|
if (!root) throw new Error("Not in a Majlis project. Run `majlis init` first.");
|
|
5080
5179
|
const db = getDb(root);
|
|
5081
5180
|
const exp = resolveExperimentArg(db, args);
|
|
5181
|
+
if (args.includes("--reject")) {
|
|
5182
|
+
transition(exp.status, "resolved" /* RESOLVED */);
|
|
5183
|
+
const reason = getFlagValue(args, "--reason") ?? "Human rejected after verification review";
|
|
5184
|
+
db.transaction(() => {
|
|
5185
|
+
insertDeadEnd(
|
|
5186
|
+
db,
|
|
5187
|
+
exp.id,
|
|
5188
|
+
exp.hypothesis ?? exp.slug,
|
|
5189
|
+
reason,
|
|
5190
|
+
`Human rejection: ${reason}`,
|
|
5191
|
+
exp.sub_type,
|
|
5192
|
+
"procedural"
|
|
5193
|
+
);
|
|
5194
|
+
updateExperimentStatus(db, exp.id, "resolved");
|
|
5195
|
+
updateExperimentStatus(db, exp.id, "dead_end");
|
|
5196
|
+
if (exp.sub_type) {
|
|
5197
|
+
incrementSubTypeFailure(db, exp.sub_type, exp.id, "rejected");
|
|
5198
|
+
}
|
|
5199
|
+
})();
|
|
5200
|
+
handleDeadEndGit(exp, root);
|
|
5201
|
+
const weakened = cascadeChainInvalidation(db, exp.slug);
|
|
5202
|
+
if (weakened > 0) warn(`Weakened chain: ${weakened} downstream experiment(s) depend on ${exp.slug}.`);
|
|
5203
|
+
info(`Experiment ${exp.slug} dead-ended by human rejection: ${reason}`);
|
|
5204
|
+
return;
|
|
5205
|
+
}
|
|
5082
5206
|
transition(exp.status, "resolved" /* RESOLVED */);
|
|
5083
5207
|
await resolve2(db, exp, root);
|
|
5084
5208
|
}
|
|
@@ -5252,6 +5376,8 @@ ${hypoContent.slice(0, 8e3)}`;
|
|
|
5252
5376
|
);
|
|
5253
5377
|
adminTransitionAndPersist(db, exp.id, "building", "dead_end" /* DEAD_END */, "revert");
|
|
5254
5378
|
handleDeadEndGit(exp, root);
|
|
5379
|
+
const weakened = cascadeChainInvalidation(db, exp.slug);
|
|
5380
|
+
if (weakened > 0) warn(`Weakened chain: ${weakened} downstream experiment(s) depend on ${exp.slug}.`);
|
|
5255
5381
|
info(`Builder abandoned ${exp.slug}: ${result.structured.abandon.reason}`);
|
|
5256
5382
|
return;
|
|
5257
5383
|
}
|
|
@@ -5322,6 +5448,8 @@ Error: ${errMsg.slice(0, 500)}`
|
|
|
5322
5448
|
);
|
|
5323
5449
|
adminTransitionAndPersist(db, exp.id, "building", "dead_end" /* DEAD_END */, "revert");
|
|
5324
5450
|
handleDeadEndGit(exp, root);
|
|
5451
|
+
const weakenedTrunc = cascadeChainInvalidation(db, exp.slug);
|
|
5452
|
+
if (weakenedTrunc > 0) warn(`Weakened chain: ${weakenedTrunc} downstream experiment(s) depend on ${exp.slug}.`);
|
|
5325
5453
|
info(`Builder abandoned ${exp.slug} (recovered from truncation): ${recovery.data.abandon.reason}`);
|
|
5326
5454
|
} else {
|
|
5327
5455
|
const tail = result.output.slice(-2e3).trim();
|
|
@@ -6180,6 +6308,8 @@ ${gitDiff.slice(0, 15e3)}
|
|
|
6180
6308
|
if (exp.gate_rejection_reason) clearGateRejection(db, exp.id);
|
|
6181
6309
|
adminTransitionAndPersist(db, exp.id, exp.status, "dead_end" /* DEAD_END */, "revert");
|
|
6182
6310
|
handleDeadEndGit(exp, root);
|
|
6311
|
+
const weakened = cascadeChainInvalidation(db, exp.slug);
|
|
6312
|
+
if (weakened > 0) warn(`Weakened chain: ${weakened} downstream experiment(s) depend on ${exp.slug}.`);
|
|
6183
6313
|
info(`Experiment ${exp.slug} reverted to dead-end.`);
|
|
6184
6314
|
info(`Constraint: ${structuralConstraint.slice(0, 120)}${structuralConstraint.length > 120 ? "..." : ""}`);
|
|
6185
6315
|
}
|
|
@@ -6550,6 +6680,50 @@ async function audit(args) {
|
|
|
6550
6680
|
const root = findProjectRoot();
|
|
6551
6681
|
if (!root) throw new Error("Not in a Majlis project. Run `majlis init` first.");
|
|
6552
6682
|
const db = getDb(root);
|
|
6683
|
+
if (args.includes("--accept")) {
|
|
6684
|
+
const proposal = getPendingAuditProposal(db);
|
|
6685
|
+
if (!proposal) {
|
|
6686
|
+
warn("No pending audit proposal to accept.");
|
|
6687
|
+
return;
|
|
6688
|
+
}
|
|
6689
|
+
const config2 = loadConfig(root);
|
|
6690
|
+
const previousObjective = config2.project?.objective ?? "";
|
|
6691
|
+
const configPath = path15.join(root, ".majlis", "config.json");
|
|
6692
|
+
const rawConfig = JSON.parse(fs15.readFileSync(configPath, "utf-8"));
|
|
6693
|
+
rawConfig.project = rawConfig.project || {};
|
|
6694
|
+
rawConfig.project.objective = proposal.proposed_objective;
|
|
6695
|
+
fs15.writeFileSync(configPath, JSON.stringify(rawConfig, null, 2) + "\n");
|
|
6696
|
+
resetConfigCache();
|
|
6697
|
+
insertObjectiveHistory(db, proposal.proposed_objective, previousObjective, proposal.reason, "audit");
|
|
6698
|
+
const activeExps = listActiveExperiments(db);
|
|
6699
|
+
for (const exp of activeExps) {
|
|
6700
|
+
insertNote(
|
|
6701
|
+
db,
|
|
6702
|
+
null,
|
|
6703
|
+
exp.id,
|
|
6704
|
+
"objective-change",
|
|
6705
|
+
`Objective changed: "${previousObjective}" \u2192 "${proposal.proposed_objective}"`
|
|
6706
|
+
);
|
|
6707
|
+
adminTransitionAndPersist(db, exp.id, exp.status, "classified" /* CLASSIFIED */, "objective_reset");
|
|
6708
|
+
}
|
|
6709
|
+
resolveAuditProposal(db, proposal.id, "accepted");
|
|
6710
|
+
autoCommit(root, `audit: accept objective rewrite`);
|
|
6711
|
+
success(`Objective updated: "${proposal.proposed_objective}"`);
|
|
6712
|
+
if (activeExps.length > 0) {
|
|
6713
|
+
info(`${activeExps.length} active experiment(s) reset to classified.`);
|
|
6714
|
+
}
|
|
6715
|
+
return;
|
|
6716
|
+
}
|
|
6717
|
+
if (args.includes("--reject")) {
|
|
6718
|
+
const proposal = getPendingAuditProposal(db);
|
|
6719
|
+
if (!proposal) {
|
|
6720
|
+
warn("No pending audit proposal to reject.");
|
|
6721
|
+
return;
|
|
6722
|
+
}
|
|
6723
|
+
resolveAuditProposal(db, proposal.id, "rejected");
|
|
6724
|
+
info("Audit proposal rejected.");
|
|
6725
|
+
return;
|
|
6726
|
+
}
|
|
6553
6727
|
const objective = args.filter((a) => !a.startsWith("--")).join(" ");
|
|
6554
6728
|
const config = loadConfig(root);
|
|
6555
6729
|
const experiments = listAllExperiments(db);
|
|
@@ -6599,13 +6773,33 @@ Answer these questions:
|
|
|
6599
6773
|
2. Is the current classification serving that objective? Or has the taxonomy become self-referential?
|
|
6600
6774
|
3. What would we do differently if we started from scratch with what we now know?
|
|
6601
6775
|
4. Is there a simpler formulation? If the classification has grown complex, something may be wrong.
|
|
6776
|
+
5. If the classification is fundamentally misaligned, propose a rewrite.
|
|
6777
|
+
Include: <!-- majlis-json {"objective_rewrite": {"proposed_objective": "...", "reason": "..."}} -->
|
|
6778
|
+
Only include objective_rewrite if genuinely needed.
|
|
6602
6779
|
|
|
6603
6780
|
Output: either "classification confirmed \u2014 continue" or "re-classify from X" with a specific proposal.`;
|
|
6604
6781
|
const result = await spawnAgent("builder", {
|
|
6605
6782
|
synthesis,
|
|
6606
6783
|
taskPrompt: auditPrompt
|
|
6607
6784
|
}, root);
|
|
6608
|
-
|
|
6785
|
+
const structured = result.structured;
|
|
6786
|
+
let rewrite = structured?.objective_rewrite;
|
|
6787
|
+
if (!rewrite && result.output) {
|
|
6788
|
+
const extracted = await extractStructuredData("builder", result.output);
|
|
6789
|
+
rewrite = extracted.data?.objective_rewrite;
|
|
6790
|
+
}
|
|
6791
|
+
if (rewrite) {
|
|
6792
|
+
insertAuditProposal(db, rewrite.proposed_objective, rewrite.reason, result.output.slice(0, 5e3));
|
|
6793
|
+
console.log();
|
|
6794
|
+
header("Objective Rewrite Proposed");
|
|
6795
|
+
console.log(` Current: ${config.project?.objective ?? "(none)"}`);
|
|
6796
|
+
console.log(` Proposed: ${rewrite.proposed_objective}`);
|
|
6797
|
+
console.log(` Reason: ${rewrite.reason}`);
|
|
6798
|
+
console.log();
|
|
6799
|
+
info("Run `majlis audit --accept` or `majlis audit --reject`.");
|
|
6800
|
+
} else {
|
|
6801
|
+
success("Purpose audit complete. Review the output above.");
|
|
6802
|
+
}
|
|
6609
6803
|
}
|
|
6610
6804
|
var fs15, path15;
|
|
6611
6805
|
var init_audit = __esm({
|
|
@@ -6615,8 +6809,12 @@ var init_audit = __esm({
|
|
|
6615
6809
|
path15 = __toESM(require("path"));
|
|
6616
6810
|
init_connection();
|
|
6617
6811
|
init_queries();
|
|
6812
|
+
init_machine();
|
|
6813
|
+
init_types2();
|
|
6618
6814
|
init_spawn();
|
|
6815
|
+
init_parse();
|
|
6619
6816
|
init_config();
|
|
6817
|
+
init_git();
|
|
6620
6818
|
init_format();
|
|
6621
6819
|
}
|
|
6622
6820
|
});
|
|
@@ -6674,6 +6872,8 @@ async function runNextStep(db, exp, config, root, isJson, overrideGate = false)
|
|
|
6674
6872
|
);
|
|
6675
6873
|
adminTransitionAndPersist(db, exp.id, exp.status, "dead_end" /* DEAD_END */, "circuit_breaker");
|
|
6676
6874
|
handleDeadEndGit(exp, root);
|
|
6875
|
+
const weakened = cascadeChainInvalidation(db, exp.slug);
|
|
6876
|
+
if (weakened > 0) warn(`Weakened chain: ${weakened} downstream experiment(s) depend on ${exp.slug}.`);
|
|
6677
6877
|
warn("Experiment dead-ended. Triggering Maqasid Check (purpose audit).");
|
|
6678
6878
|
await audit([config.project?.objective ?? ""]);
|
|
6679
6879
|
return;
|
|
@@ -6688,6 +6888,9 @@ async function runNextStep(db, exp, config, root, isJson, overrideGate = false)
|
|
|
6688
6888
|
return;
|
|
6689
6889
|
}
|
|
6690
6890
|
}
|
|
6891
|
+
if (exp.chain_weakened_by) {
|
|
6892
|
+
warn(`Experiment ${exp.slug} depends on ${exp.chain_weakened_by} (dead-ended). Chain integrity weakened.`);
|
|
6893
|
+
}
|
|
6691
6894
|
const sessionsSinceCompression = getSessionsSinceCompression(db);
|
|
6692
6895
|
if (sessionsSinceCompression >= config.cycle.compression_interval) {
|
|
6693
6896
|
warn(
|
|
@@ -6706,6 +6909,11 @@ async function runNextStep(db, exp, config, root, isJson, overrideGate = false)
|
|
|
6706
6909
|
}));
|
|
6707
6910
|
return;
|
|
6708
6911
|
}
|
|
6912
|
+
if (nextStep === "resolved" /* RESOLVED */ && config.cycle.require_human_verify) {
|
|
6913
|
+
info(`${exp.slug} verified. Human review required.`);
|
|
6914
|
+
info("Run `majlis resolve` to proceed or `majlis resolve --reject` to dead-end.");
|
|
6915
|
+
return;
|
|
6916
|
+
}
|
|
6709
6917
|
info(`${exp.slug}: ${exp.status} \u2192 ${nextStep}`);
|
|
6710
6918
|
await executeStep(nextStep, exp, root);
|
|
6711
6919
|
}
|
|
@@ -6723,6 +6931,21 @@ async function runAutoLoop(db, exp, config, root, isJson) {
|
|
|
6723
6931
|
info("Stopping auto mode. Use `majlis next --override-gate` or `majlis revert`.");
|
|
6724
6932
|
break;
|
|
6725
6933
|
}
|
|
6934
|
+
if (exp.chain_weakened_by) {
|
|
6935
|
+
warn(`Experiment ${exp.slug} has weakened chain (depends on dead-ended ${exp.chain_weakened_by}). Auto-dead-ending.`);
|
|
6936
|
+
insertDeadEnd(
|
|
6937
|
+
db,
|
|
6938
|
+
exp.id,
|
|
6939
|
+
exp.hypothesis ?? exp.slug,
|
|
6940
|
+
`Upstream dependency ${exp.chain_weakened_by} is dead-ended`,
|
|
6941
|
+
`Chain invalidated: depends on ${exp.chain_weakened_by}`,
|
|
6942
|
+
exp.sub_type,
|
|
6943
|
+
"procedural"
|
|
6944
|
+
);
|
|
6945
|
+
adminTransitionAndPersist(db, exp.id, exp.status, "dead_end" /* DEAD_END */, "circuit_breaker");
|
|
6946
|
+
handleDeadEndGit(exp, root);
|
|
6947
|
+
continue;
|
|
6948
|
+
}
|
|
6726
6949
|
if (isTerminal(exp.status)) {
|
|
6727
6950
|
success(`Experiment ${exp.slug} reached terminal state: ${exp.status}`);
|
|
6728
6951
|
break;
|
|
@@ -6740,6 +6963,8 @@ async function runAutoLoop(db, exp, config, root, isJson) {
|
|
|
6740
6963
|
);
|
|
6741
6964
|
adminTransitionAndPersist(db, exp.id, exp.status, "dead_end" /* DEAD_END */, "circuit_breaker");
|
|
6742
6965
|
handleDeadEndGit(exp, root);
|
|
6966
|
+
const weakened = cascadeChainInvalidation(db, exp.slug);
|
|
6967
|
+
if (weakened > 0) warn(`Weakened chain: ${weakened} downstream experiment(s) depend on ${exp.slug}.`);
|
|
6743
6968
|
await audit([config.project?.objective ?? ""]);
|
|
6744
6969
|
break;
|
|
6745
6970
|
}
|
|
@@ -6748,6 +6973,10 @@ async function runAutoLoop(db, exp, config, root, isJson) {
|
|
|
6748
6973
|
const expHasDoubts = hasDoubts(db, exp.id);
|
|
6749
6974
|
const expHasChallenges = hasChallenges(db, exp.id);
|
|
6750
6975
|
const nextStep = determineNextStep(exp, valid, expHasDoubts, expHasChallenges);
|
|
6976
|
+
if (nextStep === "resolved" /* RESOLVED */ && config.cycle.require_human_verify) {
|
|
6977
|
+
info("Pausing at verified \u2014 human review required.");
|
|
6978
|
+
break;
|
|
6979
|
+
}
|
|
6751
6980
|
info(`[${iteration}/${MAX_ITERATIONS}] ${exp.slug}: ${exp.status} \u2192 ${nextStep}`);
|
|
6752
6981
|
await executeStep(nextStep, exp, root);
|
|
6753
6982
|
}
|
|
@@ -6908,6 +7137,8 @@ async function run(args) {
|
|
|
6908
7137
|
"revert"
|
|
6909
7138
|
);
|
|
6910
7139
|
handleDeadEndGit(afterStep, root);
|
|
7140
|
+
const w1 = cascadeChainInvalidation(db, afterStep.slug);
|
|
7141
|
+
if (w1 > 0) warn(`Weakened chain: ${w1} downstream experiment(s) depend on ${afterStep.slug}.`);
|
|
6911
7142
|
continue;
|
|
6912
7143
|
}
|
|
6913
7144
|
} catch (err) {
|
|
@@ -6926,6 +7157,8 @@ async function run(args) {
|
|
|
6926
7157
|
);
|
|
6927
7158
|
adminTransitionAndPersist(db, exp.id, exp.status, "dead_end" /* DEAD_END */, "error_recovery");
|
|
6928
7159
|
handleDeadEndGit(exp, root);
|
|
7160
|
+
const w2 = cascadeChainInvalidation(db, exp.slug);
|
|
7161
|
+
if (w2 > 0) warn(`Weakened chain: ${w2} downstream experiment(s) depend on ${exp.slug}.`);
|
|
6929
7162
|
} catch (innerErr) {
|
|
6930
7163
|
const innerMsg = innerErr instanceof Error ? innerErr.message : String(innerErr);
|
|
6931
7164
|
warn(`Could not record dead-end: ${innerMsg}`);
|
|
@@ -8964,6 +9197,8 @@ Cycle:
|
|
|
8964
9197
|
verify [experiment] Spawn verifier agent
|
|
8965
9198
|
gate [experiment] Spawn gatekeeper agent
|
|
8966
9199
|
resolve [experiment] Route based on verification grades
|
|
9200
|
+
--reject Force dead-end (human override)
|
|
9201
|
+
--reason "text" Reason for rejection (with --reject)
|
|
8967
9202
|
compress Spawn compressor agent
|
|
8968
9203
|
|
|
8969
9204
|
Classification:
|
|
@@ -8980,6 +9215,8 @@ Queries:
|
|
|
8980
9215
|
|
|
8981
9216
|
Audit:
|
|
8982
9217
|
audit "objective" Maqasid check \u2014 is the frame right?
|
|
9218
|
+
--accept Accept pending objective rewrite
|
|
9219
|
+
--reject Reject pending objective rewrite
|
|
8983
9220
|
diagnose ["focus area"] Deep diagnosis \u2014 root causes, patterns, gaps
|
|
8984
9221
|
|
|
8985
9222
|
Sessions:
|