create-principles-disciple 1.146.8 → 1.146.9
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/_release/product-identity.json +1 -1
- package/console/dist/server/models/ExaminerEvidenceModel.d.ts +159 -0
- package/console/dist/server/models/ExaminerEvidenceModel.js +274 -0
- package/console/dist/server/models/ReceiptsConsoleModel.js +15 -1
- package/console/dist/server/routes/examiner-executor.d.ts +40 -4
- package/console/dist/server/routes/examiner-executor.js +54 -45
- package/console/dist/server/routes/examiner-runs.d.ts +196 -0
- package/console/dist/server/routes/examiner-runs.js +938 -0
- package/console/dist/server/routes/examiner-study-inputs.d.ts +147 -0
- package/console/dist/server/routes/examiner-study-inputs.js +263 -0
- package/console/dist/server/routes/examiner.d.ts +26 -17
- package/console/dist/server/routes/examiner.js +261 -12
- package/console/dist/types.d.ts +1 -0
- package/console/dist/web/assets/app.css +92 -0
- package/console/dist/web/assets/app.js +38 -32
- package/console/lab/lib/challenge-openclaw-host.mjs +17 -0
- package/console/lab/lib/challenge-runner.mjs +9 -0
- package/console/lab/lib/examiner-study.mjs +55 -0
- package/package.json +2 -2
- package/release-manager/package.json +1 -1
|
@@ -138,6 +138,23 @@ function probeOpenclawVersion(openclawBin, openclawPrefixArgs, versionProbe) {
|
|
|
138
138
|
return version;
|
|
139
139
|
}
|
|
140
140
|
|
|
141
|
+
/**
|
|
142
|
+
* SPEC-PD-EXAMINER-001 v0.10.1 §12.3 — read-only CLI reachability probe for
|
|
143
|
+
* the Console host dry-run. Same local `--version` process as transport
|
|
144
|
+
* creation, but NEVER throws and never creates anything: the result is a
|
|
145
|
+
* structured verdict the dry-run can show as a Gate 2 prerequisite. The
|
|
146
|
+
* binary defaults to the FIXED literal 'openclaw'; callers that pass an
|
|
147
|
+
* executable path take responsibility for it (the console never does).
|
|
148
|
+
*/
|
|
149
|
+
export function probeOpenClawCli({ openclawBin = 'openclaw', openclawPrefixArgs = [], versionProbe = null } = {}) {
|
|
150
|
+
try {
|
|
151
|
+
const version = probeOpenclawVersion(openclawBin, openclawPrefixArgs, versionProbe);
|
|
152
|
+
return { ok: true, cliVersion: version, reason: null };
|
|
153
|
+
} catch (err) {
|
|
154
|
+
return { ok: false, cliVersion: null, reason: err && err.message ? err.message : String(err) };
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
141
158
|
/** Same suffix discipline as verifyF2ProbeEvidence.sameModel — a provider-
|
|
142
159
|
* prefixed model id ("zai/glm-5.3-flash") matches its bare id. */
|
|
143
160
|
const sameModel = (a, b) => a === b || (typeof a === 'string' && typeof b === 'string' && (a.endsWith(`/${b}`) || b.endsWith(`/${a}`)));
|
|
@@ -410,6 +410,7 @@ export async function runChallengeStudy({
|
|
|
410
410
|
owner = 'challenge-runner',
|
|
411
411
|
deps = {},
|
|
412
412
|
execution = null,
|
|
413
|
+
admissionCheck = null,
|
|
413
414
|
}) {
|
|
414
415
|
const declaredMode = execution && execution.mode !== undefined ? execution.mode : 'offline-stub';
|
|
415
416
|
if (!RUNNER_EXECUTION_MODES.includes(declaredMode)) {
|
|
@@ -452,6 +453,14 @@ export async function runChallengeStudy({
|
|
|
452
453
|
// unchanged. Same run-scoped discipline as the unknown streak.
|
|
453
454
|
let consecutiveCapacityFailures = 0;
|
|
454
455
|
try {
|
|
456
|
+
// P1-3 (offline↔async single-active): the caller-injected admission check
|
|
457
|
+
// runs FIRST under this study write lock — before RUN_STARTED, before any
|
|
458
|
+
// attempt reservation and before any actor is constructed. A refusal here
|
|
459
|
+
// throws, the lock is released by the catch below, and the ledger keeps no
|
|
460
|
+
// half-started run.
|
|
461
|
+
if (typeof admissionCheck === 'function') {
|
|
462
|
+
await admissionCheck({ studyDir });
|
|
463
|
+
}
|
|
455
464
|
// P1-4 server-enforced readiness: identity/path ownership are the caller's
|
|
456
465
|
// gate (the console resolves the directory from its own enumeration and
|
|
457
466
|
// verifies the write permission marker); the FROZEN study is re-verified
|
|
@@ -455,6 +455,7 @@ export function buildExaminerStudyManifest({
|
|
|
455
455
|
invalidationPolicy,
|
|
456
456
|
armPayloadHashes = null,
|
|
457
457
|
authorizationRef = null,
|
|
458
|
+
productionSnapshotHash = null,
|
|
458
459
|
}) {
|
|
459
460
|
if (!text(studyId)) throw new Error('buildExaminerStudyManifest: studyId required');
|
|
460
461
|
if (!/^[A-Z0-9][A-Z0-9-]*$/.test(studyId)) throw new Error(`buildExaminerStudyManifest: studyId '${studyId}' must be UPPER-CASE with digits/dashes`);
|
|
@@ -511,6 +512,11 @@ export function buildExaminerStudyManifest({
|
|
|
511
512
|
analysisPlanHash: hashOfCanonical(analysisPlan),
|
|
512
513
|
invalidationPolicyHash: hashOfCanonical(invalidationPolicy),
|
|
513
514
|
authorizationRef,
|
|
515
|
+
// v0.10.1 P1-1: the frozen production snapshot rides INSIDE the manifest
|
|
516
|
+
// (and therefore inside the manifestHash → binding → anchor chain).
|
|
517
|
+
// Conditional like armPayloadHashes so a v0.9-shaped manifest stays
|
|
518
|
+
// byte-identical with the historical field set.
|
|
519
|
+
...(productionSnapshotHash ? { productionSnapshotHash } : {}),
|
|
514
520
|
};
|
|
515
521
|
return { ...core, manifestHash: hashOfCanonical(core) };
|
|
516
522
|
}
|
|
@@ -730,6 +736,36 @@ export function computeExaminerStudyBindings(studyDir) {
|
|
|
730
736
|
if (hashes.examinerManifestHash?.value !== manifest.manifestHash) push('hashes.examinerManifestHash != manifest.manifestHash');
|
|
731
737
|
if (hashes.pairAssignmentHash?.value !== pair.assignmentHash) push('hashes.pairAssignmentHash != pair assignment hash');
|
|
732
738
|
|
|
739
|
+
// --- production snapshot (v0.10.1 §4.4/§6.4) ------------------------------
|
|
740
|
+
// The frozen production baseline is PART of the preregistration evidence:
|
|
741
|
+
// when the file exists it is hash-bound to the manifest and the binding; a
|
|
742
|
+
// missing file beside a manifest that declares a snapshot hash is drift;
|
|
743
|
+
// no file AND no manifest field is the v0.9 legacy shape (verified studies
|
|
744
|
+
// keep recomputing the exact historical binding). The snapshot content
|
|
745
|
+
// carries no self-hash, so the chain snapshot→manifestHash→binding→anchor
|
|
746
|
+
// has no cycle.
|
|
747
|
+
let productionSnapshotHash = null;
|
|
748
|
+
const snapshotPath = path.join(studyDir, 'production-snapshot.json');
|
|
749
|
+
if (fs.existsSync(snapshotPath)) {
|
|
750
|
+
let snapshotParsed;
|
|
751
|
+
try {
|
|
752
|
+
snapshotParsed = JSON.parse(fs.readFileSync(snapshotPath, 'utf8'));
|
|
753
|
+
} catch (e) {
|
|
754
|
+
push(`production-snapshot.json is not valid JSON: ${e.message}`);
|
|
755
|
+
snapshotParsed = null;
|
|
756
|
+
}
|
|
757
|
+
if (snapshotParsed !== null && typeof snapshotParsed === 'object' && !Array.isArray(snapshotParsed)) {
|
|
758
|
+
productionSnapshotHash = hashOfCanonical(snapshotParsed);
|
|
759
|
+
if (manifest.productionSnapshotHash !== productionSnapshotHash) {
|
|
760
|
+
push('production-snapshot.json hash != manifest.productionSnapshotHash — the frozen production baseline was modified after freezing');
|
|
761
|
+
}
|
|
762
|
+
} else if (snapshotParsed !== null) {
|
|
763
|
+
push('production-snapshot.json must be a JSON object');
|
|
764
|
+
}
|
|
765
|
+
} else if (manifest.productionSnapshotHash !== undefined) {
|
|
766
|
+
push('manifest.productionSnapshotHash declared but production-snapshot.json is missing — the frozen production baseline cannot be verified');
|
|
767
|
+
}
|
|
768
|
+
|
|
733
769
|
const binding = {
|
|
734
770
|
schema: PREREG_BINDING_SCHEMA,
|
|
735
771
|
studyId: manifest.studyId ?? null,
|
|
@@ -749,6 +785,9 @@ export function computeExaminerStudyBindings(studyDir) {
|
|
|
749
785
|
// definition after freezing (even with every file re-hashed) moves this.
|
|
750
786
|
primaryEndpointHash: hashOfCanonical(manifest.primaryEndpoint ?? null),
|
|
751
787
|
armPayloadHashes,
|
|
788
|
+
// P1-1: present ONLY when the study freezes a production snapshot — the
|
|
789
|
+
// v0.9 historical binding field set stays byte-identical otherwise.
|
|
790
|
+
...(productionSnapshotHash ? { productionSnapshotHash } : {}),
|
|
752
791
|
plannedPairs: manifest.plannedPairs ?? null,
|
|
753
792
|
repetitionsPerCase: manifest.repetitionsPerCase ?? null,
|
|
754
793
|
};
|
|
@@ -961,9 +1000,19 @@ export function writeExaminerStudyArtifacts(input) {
|
|
|
961
1000
|
analysisPlan, invalidationPolicy, hostManifest, modelManifest,
|
|
962
1001
|
scorerVersion, seed, repetitionsPerCase, authorizationRef = null,
|
|
963
1002
|
goldProvenance = 'SYNTHETIC_OFFLINE',
|
|
1003
|
+
productionSnapshot = null,
|
|
964
1004
|
} = input;
|
|
965
1005
|
if (!studyDir || typeof studyDir !== 'string') throw new Error('writeExaminerStudyArtifacts: studyDir required');
|
|
966
1006
|
if (fs.existsSync(studyDir)) throw new Error(`writeExaminerStudyArtifacts: '${studyDir}' already exists — a study identity is created once; overwriting is refused (create a NEW study id instead)`);
|
|
1007
|
+
// P1-1/rc-1: the production snapshot arrives as external runtime data. Freeze
|
|
1008
|
+
// it as the JSON it will be STORED as: canonical hashing keeps object keys
|
|
1009
|
+
// whose value is `undefined`, while JSON serialization drops them — hashing
|
|
1010
|
+
// the raw in-memory object would disagree with the file on disk and report
|
|
1011
|
+
// false drift. Binding verification hashes the written bytes; the manifest
|
|
1012
|
+
// must hash the same representation.
|
|
1013
|
+
const frozenProductionSnapshot = productionSnapshot === null
|
|
1014
|
+
? null
|
|
1015
|
+
: JSON.parse(JSON.stringify(productionSnapshot));
|
|
967
1016
|
const frozenArea = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', 'challenge-studies');
|
|
968
1017
|
const resolved = path.resolve(studyDir);
|
|
969
1018
|
const norm = (p) => (process.platform === 'win32' ? p.toLowerCase() : p);
|
|
@@ -1011,6 +1060,9 @@ export function writeExaminerStudyArtifacts(input) {
|
|
|
1011
1060
|
invalidationPolicy,
|
|
1012
1061
|
armPayloadHashes: { control: armPayloads.arms.control.payloadHash, treatment: armPayloads.arms.treatment.payloadHash },
|
|
1013
1062
|
authorizationRef,
|
|
1063
|
+
// P1-1: the snapshot is gathered BEFORE the freeze and rides the full
|
|
1064
|
+
// manifest → binding → anchor chain (no post-freeze append can touch it).
|
|
1065
|
+
...(frozenProductionSnapshot !== null ? { productionSnapshotHash: hashOfCanonical(frozenProductionSnapshot) } : {}),
|
|
1014
1066
|
});
|
|
1015
1067
|
const prereg = {
|
|
1016
1068
|
studyId: input.studyId,
|
|
@@ -1046,6 +1098,9 @@ export function writeExaminerStudyArtifacts(input) {
|
|
|
1046
1098
|
writeJson('scoring-contract.json', scoringContract);
|
|
1047
1099
|
writeJson('principle-frozen.json', principleFrozen);
|
|
1048
1100
|
writeJson('pain-mechanism-mapping.json', mapping);
|
|
1101
|
+
// P1-1: the production baseline freezes WITH the study (inside the binding
|
|
1102
|
+
// verification below) — not as a post-freeze append.
|
|
1103
|
+
if (frozenProductionSnapshot !== null) writeJson('production-snapshot.json', frozenProductionSnapshot);
|
|
1049
1104
|
writeJson('input-manifest.json', { expectedSourceHashes: { principleContentHash: hashOfCanonical(principleFrozen.contentJson) } });
|
|
1050
1105
|
writeJson('hashes.json', {
|
|
1051
1106
|
preregistrationHash: { value: hashOfCanonical(prereg) },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-principles-disciple",
|
|
3
|
-
"version": "1.146.
|
|
3
|
+
"version": "1.146.9",
|
|
4
4
|
"description": "Interactive CLI installer for Principles Disciple OpenClaw plugin",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -98,5 +98,5 @@
|
|
|
98
98
|
"pd": {
|
|
99
99
|
"bundledPluginVersion": "2.2.13"
|
|
100
100
|
},
|
|
101
|
-
"gitHead": "
|
|
101
|
+
"gitHead": "8e0cdc607ee5d25e0b66a0655a6e0ce033a1fe99"
|
|
102
102
|
}
|