create-principles-disciple 1.145.8 → 1.145.10
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 +2 -2
- package/codex-adapter/dist/ingestion/admission.d.ts +1 -0
- package/codex-adapter/dist/ingestion/admission.js +1 -0
- package/codex-adapter/dist/ingestion/ingestion.d.ts +2 -0
- package/codex-adapter/dist/ingestion/ingestion.js +3 -3
- package/codex-adapter/dist/pd-hook.d.ts +0 -1
- package/codex-adapter/dist/pd-hook.js +20 -32
- package/codex-adapter/package.json +1 -1
- package/console/dist/server/routes/approvals.js +7 -0
- package/core/dist/runtime-v2/activation/activation-types.d.ts +2 -0
- package/core/dist/runtime-v2/activation/activation-types.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/activation-types.js.map +1 -1
- package/core/dist/runtime-v2/activation/sqlite-approval-store.d.ts.map +1 -1
- package/core/dist/runtime-v2/activation/sqlite-approval-store.js +64 -10
- package/core/dist/runtime-v2/activation/sqlite-approval-store.js.map +1 -1
- package/core/dist/runtime-v2/adapter/artificer-l2-adapter.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/artificer-l2-adapter.js +23 -1
- package/core/dist/runtime-v2/adapter/artificer-l2-adapter.js.map +1 -1
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts +9 -0
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.js +39 -5
- package/core/dist/runtime-v2/adapter/l2-agent-loop-adapter.js.map +1 -1
- package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.d.ts +4 -0
- package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.js +18 -4
- package/core/dist/runtime-v2/adapter/openclaw-cli-runtime-adapter.js.map +1 -1
- package/core/dist/runtime-v2/adapter/output-schema-registry.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/output-schema-registry.js +5 -0
- package/core/dist/runtime-v2/adapter/output-schema-registry.js.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts +26 -0
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.d.ts.map +1 -1
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js +88 -13
- package/core/dist/runtime-v2/adapter/pi-ai-runtime-adapter.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js +1 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.d.ts.map +1 -1
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js +8 -0
- package/core/dist/runtime-v2/feature-flags/feature-flag-lifecycle.js.map +1 -1
- package/core/dist/runtime-v2/index.d.ts +3 -0
- package/core/dist/runtime-v2/index.d.ts.map +1 -1
- package/core/dist/runtime-v2/index.js +7 -0
- package/core/dist/runtime-v2/index.js.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts +2 -2
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-prompt-builder.js +7 -7
- package/core/dist/runtime-v2/internalization/artificer-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/artificer-runner.js +5 -2
- package/core/dist/runtime-v2/internalization/artificer-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts +3 -0
- package/core/dist/runtime-v2/internalization/evaluator-runner.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/evaluator-runner.js +231 -37
- package/core/dist/runtime-v2/internalization/evaluator-runner.js.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-transition-decision.d.ts +3 -0
- package/core/dist/runtime-v2/internalization/internalization-transition-decision.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/internalization-transition-decision.js +7 -1
- package/core/dist/runtime-v2/internalization/internalization-transition-decision.js.map +1 -1
- package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts +5 -0
- package/core/dist/runtime-v2/internalization/pitask-metadata.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/pitask-metadata.js +8 -0
- package/core/dist/runtime-v2/internalization/pitask-metadata.js.map +1 -1
- package/core/dist/runtime-v2/internalization/refiner-sandbox-wrapper.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/refiner-sandbox-wrapper.js +11 -26
- package/core/dist/runtime-v2/internalization/refiner-sandbox-wrapper.js.map +1 -1
- package/core/dist/runtime-v2/internalization/rule-host-input-builder.d.ts +9 -2
- package/core/dist/runtime-v2/internalization/rule-host-input-builder.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/rule-host-input-builder.js +163 -111
- package/core/dist/runtime-v2/internalization/rule-host-input-builder.js.map +1 -1
- package/core/dist/runtime-v2/internalization/rule-reliability-validation.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/rule-reliability-validation.js +12 -7
- package/core/dist/runtime-v2/internalization/rule-reliability-validation.js.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-output.d.ts +19 -2
- package/core/dist/runtime-v2/internalization/scribe-output.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/scribe-output.js +34 -11
- package/core/dist/runtime-v2/internalization/scribe-output.js.map +1 -1
- package/core/dist/runtime-v2/internalization/v2-adversarial-cases.d.ts +6 -44
- package/core/dist/runtime-v2/internalization/v2-adversarial-cases.d.ts.map +1 -1
- package/core/dist/runtime-v2/internalization/v2-adversarial-cases.js +25 -146
- package/core/dist/runtime-v2/internalization/v2-adversarial-cases.js.map +1 -1
- package/core/dist/runtime-v2/learning-lab/actor-action-output.d.ts +42 -0
- package/core/dist/runtime-v2/learning-lab/actor-action-output.d.ts.map +1 -0
- package/core/dist/runtime-v2/learning-lab/actor-action-output.js +63 -0
- package/core/dist/runtime-v2/learning-lab/actor-action-output.js.map +1 -0
- package/core/dist/runtime-v2/runtime-protocol.d.ts +17 -0
- package/core/dist/runtime-v2/runtime-protocol.d.ts.map +1 -1
- package/core/dist/runtime-v2/runtime-protocol.js +17 -0
- package/core/dist/runtime-v2/runtime-protocol.js.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.d.ts.map +1 -1
- package/core/dist/runtime-v2/store/sqlite-connection.js +4 -0
- package/core/dist/runtime-v2/store/sqlite-connection.js.map +1 -1
- package/core/dist/runtime-v2/tools/artificer-l2-tool-contract.js +9 -9
- package/core/dist/runtime-v2/tools/artificer-l2-tool-contract.js.map +1 -1
- package/core/dist/runtime-v2/trajectory-schema.d.ts.map +1 -1
- package/core/dist/runtime-v2/trajectory-schema.js +10 -1
- package/core/dist/runtime-v2/trajectory-schema.js.map +1 -1
- package/core/dist/telemetry-event.d.ts +2 -2
- package/core/dist/telemetry-event.d.ts.map +1 -1
- package/core/dist/telemetry-event.js +6 -0
- package/core/dist/telemetry-event.js.map +1 -1
- package/core/package.json +1 -1
- package/dist/installers/workbuddy-host-installer.d.ts +0 -6
- package/dist/installers/workbuddy-host-installer.d.ts.map +1 -1
- package/dist/installers/workbuddy-host-installer.js +54 -3
- package/dist/installers/workbuddy-host-installer.js.map +1 -1
- package/dist/prompts.js +1 -1
- package/dist/prompts.js.map +1 -1
- package/host-runtime/dist/behavior-history.js +4 -9
- package/host-runtime/dist/codex-rule-context-provider.d.ts +23 -0
- package/host-runtime/dist/codex-rule-context-provider.js +89 -0
- package/host-runtime/dist/governance-signal-admission.d.ts +17 -4
- package/host-runtime/dist/governance-signal-admission.js +114 -14
- package/host-runtime/dist/index.d.ts +2 -1
- package/host-runtime/dist/index.js +4 -1
- package/host-runtime/dist/internalization-consumer-cycle.js +1 -1
- package/host-runtime/dist/internalization-consumer-governance.js +3 -0
- package/host-runtime/dist/production-pain-evidence.d.ts +1 -0
- package/host-runtime/dist/production-pain-evidence.js +18 -4
- package/host-runtime/dist/production-rulehost-gate.d.ts +2 -1
- package/host-runtime/dist/production-rulehost-gate.js +45 -4
- package/host-runtime/dist/workspace-behavior-evidence.d.ts +18 -0
- package/host-runtime/dist/workspace-behavior-evidence.js +47 -0
- package/host-runtime/package.json +1 -1
- package/package.json +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.d.ts.map +1 -1
- package/pd-cli/dist/commands/runtime-internalization-run-once.js +33 -7
- package/pd-cli/dist/commands/runtime-internalization-run-once.js.map +1 -1
- package/pd-cli/dist/commands/workbuddy-worker.d.ts +5 -0
- package/pd-cli/dist/commands/workbuddy-worker.d.ts.map +1 -1
- package/pd-cli/dist/commands/workbuddy-worker.js +8 -1
- package/pd-cli/dist/commands/workbuddy-worker.js.map +1 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.d.ts.map +1 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.js +4 -1
- package/pd-cli/dist/services/rulehost-pipeline-runner.js.map +1 -1
- package/pd-cli/package.json +1 -1
- package/plugin/dist/bundle.js +472 -466
- package/plugin/dist/rulehost-evidence.js +43 -43
- package/release-manager/dist/installers/workbuddy-host-installer.d.ts +0 -6
- package/release-manager/dist/installers/workbuddy-host-installer.d.ts.map +1 -1
- package/release-manager/dist/installers/workbuddy-host-installer.js +54 -3
- package/release-manager/dist/installers/workbuddy-host-installer.js.map +1 -1
- package/release-manager/dist/prompts.js +1 -1
- package/release-manager/dist/prompts.js.map +1 -1
- package/release-manager/package.json +1 -1
- package/workbuddy-adapter/dist/pd-hook.js +73 -2
- package/workbuddy-adapter/package.json +1 -1
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
import fs from 'node:fs';
|
|
35
35
|
import path from 'node:path';
|
|
36
36
|
import Database from 'better-sqlite3';
|
|
37
|
-
import { collectSync, CORRECTION_SEED_KEYWORDS, buildToolFailureObservation, evaluateTriage, evaluateTriggerController, resolveSourceKind, PainToPrincipleService, PrincipleTreeLedgerAdapter, RuntimeStateManager, createDiagnosticianTaskId, disposePainSignalBridgesForWorkspace, sanitizeString, boundCorrectionEvidenceText, MAX_EVIDENCE_VALUE_CHARS, } from '@principles/core/runtime-v2';
|
|
37
|
+
import { collectSync, computeFeatureFlagsFromConfig, CORRECTION_SEED_KEYWORDS, buildToolFailureObservation, evaluateTriage, evaluateTriggerController, resolveSourceKind, PainToPrincipleService, PrincipleTreeLedgerAdapter, RuntimeStateManager, createDiagnosticianTaskId, disposePainSignalBridgesForWorkspace, sanitizeString, boundCorrectionEvidenceText, MAX_EVIDENCE_VALUE_CHARS, } from '@principles/core/runtime-v2';
|
|
38
38
|
import { deriveProductionCorrectionPainIdentity, deriveProductionToolPainIdentity, hasProductionPainSchema, PRODUCTION_WRITE_TOOLS, } from './production-pain-evidence.js';
|
|
39
39
|
import { promoteGovernanceEvidence, ensureGovernanceSchema } from './governance-observation-store.js';
|
|
40
40
|
import { loadPdConfigForPlugin } from './pd-config.js';
|
|
@@ -303,13 +303,23 @@ function ensureGovernanceAdmissionSchema(db) {
|
|
|
303
303
|
if (hasToolCalls) {
|
|
304
304
|
try {
|
|
305
305
|
db.exec('ALTER TABLE tool_calls ADD COLUMN tool_use_id TEXT');
|
|
306
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_tool_calls_session_tool_use_id ON tool_calls(session_id, tool_use_id)');
|
|
307
306
|
}
|
|
308
307
|
catch (err) {
|
|
309
308
|
const message = err instanceof Error ? err.message : String(err);
|
|
310
309
|
if (!message.includes('duplicate column name'))
|
|
311
310
|
throw err;
|
|
312
311
|
}
|
|
312
|
+
try {
|
|
313
|
+
// Additive project scope for live Codex admission rows. Existing rows
|
|
314
|
+
// deliberately remain NULL because their originating cwd is unknown.
|
|
315
|
+
db.exec('ALTER TABLE tool_calls ADD COLUMN project_dir TEXT');
|
|
316
|
+
}
|
|
317
|
+
catch (err) {
|
|
318
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
319
|
+
if (!message.includes('duplicate column name'))
|
|
320
|
+
throw err;
|
|
321
|
+
}
|
|
322
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_tool_calls_session_tool_use_id ON tool_calls(session_id, tool_use_id)');
|
|
313
323
|
}
|
|
314
324
|
})();
|
|
315
325
|
}
|
|
@@ -422,7 +432,8 @@ function toolFailureTaskPayload(fields) {
|
|
|
422
432
|
};
|
|
423
433
|
return JSON.stringify(payload);
|
|
424
434
|
}
|
|
425
|
-
function taskSubmissionPayload(candidate, workspaceDir,
|
|
435
|
+
function taskSubmissionPayload(candidate, workspaceDir, details) {
|
|
436
|
+
const { reason, canonicalPainId } = details;
|
|
426
437
|
if (candidate.kind === 'user_correction') {
|
|
427
438
|
// P1-1 privacy (review round 2): sanitize the FULL text before any
|
|
428
439
|
// truncation — a token crossing the 200-char boundary must be redacted, not
|
|
@@ -436,9 +447,14 @@ function taskSubmissionPayload(candidate, workspaceDir, reason) {
|
|
|
436
447
|
hostKind: candidate.hostKind,
|
|
437
448
|
// WorkBuddy explicit intake has no transcript observation to promote.
|
|
438
449
|
// The classified Owner statement is its input basis, not a pseudo-trace.
|
|
439
|
-
evidence: candidate.hostKind === 'workbuddy'
|
|
440
|
-
? []
|
|
441
|
-
|
|
450
|
+
evidence: candidate.hostKind === 'workbuddy'
|
|
451
|
+
? candidate.explicitOwnerStatement === true ? [] : [{
|
|
452
|
+
// WorkBuddy has no governance_observation, anchor to the canonical
|
|
453
|
+
// Pain persisted in this same trajectory.db transaction.
|
|
454
|
+
sourceRef: 'pain_event:' + (canonicalPainId ?? ''),
|
|
455
|
+
note: sanitizeString(candidate.text, workspaceDir),
|
|
456
|
+
}]
|
|
457
|
+
: [{ sourceRef: 'governance_observation:' + candidate.logicalObservationKey, note: sanitizeString(candidate.text, workspaceDir) }],
|
|
442
458
|
// SPEC-CODEX-PAIN-CLOSURE-001 CR-02 (merged from main): an explicit
|
|
443
459
|
// Owner statement rides as classified correction evidence — never
|
|
444
460
|
// summarized by an AI, never inside evidence[] pseudo-trace entries.
|
|
@@ -534,7 +550,7 @@ function admitCorrection({ db, candidate, workspaceDir, now, nowIso, keywordStor
|
|
|
534
550
|
// detection, so `detection` is optional — no ruleVersion exists for them.
|
|
535
551
|
ruleVersion: detection?.ruleVersion ?? null,
|
|
536
552
|
reason,
|
|
537
|
-
payloadJson: taskSubmissionPayload(candidate, workspaceDir, reason),
|
|
553
|
+
payloadJson: taskSubmissionPayload(candidate, workspaceDir, { reason, canonicalPainId: painId }),
|
|
538
554
|
nowIso,
|
|
539
555
|
});
|
|
540
556
|
})();
|
|
@@ -608,8 +624,11 @@ function admitToolFailure({ db, candidate, workspaceDir, nowIso }) {
|
|
|
608
624
|
else {
|
|
609
625
|
db.prepare(`INSERT INTO sessions (session_id, started_at, updated_at) VALUES (?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET updated_at = excluded.updated_at`)
|
|
610
626
|
.run(candidate.rootSessionId, nowIso, nowIso);
|
|
611
|
-
|
|
612
|
-
|
|
627
|
+
const projectDir = typeof candidate.projectDir === 'string' && path.isAbsolute(candidate.projectDir)
|
|
628
|
+
? path.resolve(candidate.projectDir)
|
|
629
|
+
: null;
|
|
630
|
+
db.prepare(`INSERT INTO tool_calls (session_id, tool_name, outcome, duration_ms, exit_code, error_type, error_message, gfi_before, gfi_after, params_json, result_preview, created_at, tool_use_id, project_dir) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
631
|
+
.run(candidate.rootSessionId, candidate.toolName, outcome.outcome, outcome.durationMs ?? null, outcome.exitCode, outcome.error ? outcome.error.split(/[\s:]/, 1)[0] : null, outcome.error ?? null, null, null, paramsJson, resultPreview, nowIso, candidate.toolUseId ?? null, projectDir);
|
|
613
632
|
reason = `tool=${candidate.toolName}; error=${outcome.error ?? `exit=${outcome.exitCode}`}; path=${relativePath}`;
|
|
614
633
|
db.prepare(`INSERT INTO pain_events (session_id, source, score, reason, severity, origin, confidence, text, canonical_pain_id, runtime_task_id, host_kind, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
615
634
|
.run(candidate.rootSessionId, sourceObservation.failureSource ?? 'tool_failure', painScore, reason, painScore >= 70 ? 'severe' : painScore >= 40 ? 'moderate' : 'mild', 'system_infer', null, null, painId, null, candidate.hostKind, nowIso);
|
|
@@ -624,7 +643,7 @@ function admitToolFailure({ db, candidate, workspaceDir, nowIso }) {
|
|
|
624
643
|
canonicalPainId: painId,
|
|
625
644
|
ruleVersion: null,
|
|
626
645
|
reason: sanitizeString(reason, workspaceDir),
|
|
627
|
-
payloadJson: taskSubmissionPayload(candidate, workspaceDir, reason),
|
|
646
|
+
payloadJson: taskSubmissionPayload(candidate, workspaceDir, { reason }),
|
|
628
647
|
nowIso,
|
|
629
648
|
});
|
|
630
649
|
}
|
|
@@ -637,8 +656,8 @@ function admitToolFailure({ db, candidate, workspaceDir, nowIso }) {
|
|
|
637
656
|
}
|
|
638
657
|
return { disposition: 'admitted', kind: 'tool_failure', logicalObservationKey: candidate.logicalObservationKey, canonicalPainId: painId, duplicate, ruleVersion: null };
|
|
639
658
|
}
|
|
640
|
-
function admitOne({ db, candidate, workspaceDir, now, nowIso, keywordStore, onDegradation }) {
|
|
641
|
-
if (candidate.hostKind !== 'codex' && !(candidate.hostKind === 'workbuddy' && candidate.kind === 'user_correction' && candidate.explicitOwnerStatement === true)) {
|
|
659
|
+
function admitOne({ db, candidate, workspaceDir, now, nowIso, keywordStore, onDegradation, trustedWorkbuddyLive }) {
|
|
660
|
+
if (candidate.hostKind !== 'codex' && !(candidate.hostKind === 'workbuddy' && candidate.kind === 'user_correction' && (candidate.explicitOwnerStatement === true || trustedWorkbuddyLive === true))) {
|
|
642
661
|
return { ok: false, reason: 'unsupported_host_kind', nextAction: 'governance signal admission accepts Codex observations or explicit WorkBuddy Owner statements' };
|
|
643
662
|
}
|
|
644
663
|
const marker = db.prepare('SELECT * FROM governance_signal_admissions WHERE logical_observation_key = ?').get(candidate.logicalObservationKey);
|
|
@@ -663,7 +682,7 @@ function admitOne({ db, candidate, workspaceDir, now, nowIso, keywordStore, onDe
|
|
|
663
682
|
* trajectory.db transaction (marker + pain row + quota together), so one
|
|
664
683
|
* failing candidate never rolls back another's admission.
|
|
665
684
|
*/
|
|
666
|
-
|
|
685
|
+
function admitGovernanceSignalsInternal(input, trustedWorkbuddyLive = false) {
|
|
667
686
|
const opened = openAdmissionStore(input.workspaceDir, input.databaseFactory);
|
|
668
687
|
if (!('db' in opened))
|
|
669
688
|
return opened;
|
|
@@ -678,7 +697,7 @@ export function admitGovernanceSignals(input) {
|
|
|
678
697
|
const outcomes = [];
|
|
679
698
|
try {
|
|
680
699
|
for (const candidate of input.candidates) {
|
|
681
|
-
outcomes.push(admitOne({ db, candidate, workspaceDir, now, nowIso, ...(input.keywordStore ? { keywordStore: input.keywordStore } : {}), ...(input.onDegradation ? { onDegradation: input.onDegradation } : {}) }));
|
|
700
|
+
outcomes.push(admitOne({ db, candidate, workspaceDir, now, nowIso, ...(input.keywordStore ? { keywordStore: input.keywordStore } : {}), ...(input.onDegradation ? { onDegradation: input.onDegradation } : {}), trustedWorkbuddyLive }));
|
|
682
701
|
}
|
|
683
702
|
return { ok: true, outcomes };
|
|
684
703
|
}
|
|
@@ -690,6 +709,87 @@ export function admitGovernanceSignals(input) {
|
|
|
690
709
|
close();
|
|
691
710
|
}
|
|
692
711
|
}
|
|
712
|
+
/** Public generic intake stays Codex + explicit WorkBuddy only. */
|
|
713
|
+
export function admitGovernanceSignals(input) {
|
|
714
|
+
return admitGovernanceSignalsInternal(input);
|
|
715
|
+
}
|
|
716
|
+
/** P0: a four-term projection of existing canonical high-precision seeds. */
|
|
717
|
+
const WORKBUDDY_AUTO_TERMS = new Set(['这是错的', '不要自作主张', '不应该这么做', '又搞错']);
|
|
718
|
+
const WORKBUDDY_MAX_PROMPT_BYTES = 16 * 1024;
|
|
719
|
+
function workbuddyP0KeywordStore() {
|
|
720
|
+
const seed = buildSharedSeedKeywordStore();
|
|
721
|
+
const terms = {};
|
|
722
|
+
for (const [term, def] of Object.entries(seed.terms)) {
|
|
723
|
+
if (WORKBUDDY_AUTO_TERMS.has(term) && def.category === 'correction' && def.precision === 'high') {
|
|
724
|
+
terms[term] = def;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
return { version: seed.version, terms };
|
|
728
|
+
}
|
|
729
|
+
/** Pure check: no DB, no filesystem, no classifier, no historical transcript. */
|
|
730
|
+
export function assessWorkbuddyLiveKeyword(text, sessionId) {
|
|
731
|
+
if (Buffer.byteLength(text, 'utf8') > WORKBUDDY_MAX_PROMPT_BYTES) {
|
|
732
|
+
return { matched: false, reason: 'prompt_too_large' };
|
|
733
|
+
}
|
|
734
|
+
const store = workbuddyP0KeywordStore();
|
|
735
|
+
// Prefer precision to recall: reject quoted/embedded/reported phrases.
|
|
736
|
+
if (!Object.keys(store.terms).some(term => text.trimStart().toLowerCase().startsWith(term.toLowerCase()))) {
|
|
737
|
+
return { matched: false, reason: 'not_a_signal' };
|
|
738
|
+
}
|
|
739
|
+
const out = collectSync(text, sessionId, store, SYNC_DETECTION_CONFIG, new Date().toISOString());
|
|
740
|
+
const matched = out.isSignal && out.strength === 'STRONG' &&
|
|
741
|
+
out.type === 'correction' && out.matchedPrecision === 'high';
|
|
742
|
+
return { matched, reason: matched ? 'matched' : 'not_a_signal' };
|
|
743
|
+
}
|
|
744
|
+
/**
|
|
745
|
+
* Narrow native event gateway: validate true current user origin and flags.
|
|
746
|
+
* The ordinary generic admission API cannot bypass this WorkBuddy gate.
|
|
747
|
+
*/
|
|
748
|
+
export function admitTrustedWorkbuddyLiveCorrection(input) {
|
|
749
|
+
const raw = input.rawEvent;
|
|
750
|
+
if (!isRecord(raw) || own(raw, 'hook_event_name') !== 'UserPromptSubmit' ||
|
|
751
|
+
own(raw, 'is_internal_continuation') !== false) {
|
|
752
|
+
return { ok: false, reason: 'native_current_user_unverified', nextAction: 'Require a real current WorkBuddy UserPromptSubmit event.' };
|
|
753
|
+
}
|
|
754
|
+
const sessionId = own(raw, 'session_id');
|
|
755
|
+
const generationId = own(raw, 'generation_id');
|
|
756
|
+
const prompt = own(raw, 'prompt');
|
|
757
|
+
if (typeof sessionId !== 'string' || !sessionId.trim() ||
|
|
758
|
+
typeof generationId !== 'string' || !generationId.trim() ||
|
|
759
|
+
typeof prompt !== 'string') {
|
|
760
|
+
return { ok: false, reason: 'native_identity_invalid', nextAction: 'Require nonblank native session_id/generation_id and prompt.' };
|
|
761
|
+
}
|
|
762
|
+
const config = loadPdConfigForPlugin(input.workspaceDir);
|
|
763
|
+
if (!config.ok)
|
|
764
|
+
return { ok: false, reason: 'workbuddy_config_invalid', nextAction: 'Repair WorkBuddy governance workspace config.' };
|
|
765
|
+
const { flags } = computeFeatureFlagsFromConfig(config.effective);
|
|
766
|
+
if (flags['host.workbuddy']?.enabled !== true || flags.workbuddy_live_keyword_pain?.enabled !== true) {
|
|
767
|
+
return { ok: false, reason: 'workbuddy_auto_disabled', nextAction: 'Explicitly enable both WorkBuddy host and live keyword Pain.' };
|
|
768
|
+
}
|
|
769
|
+
if (prompt.trimStart().startsWith('PD记录痛苦')) {
|
|
770
|
+
return { ok: false, reason: 'explicit_owner_statement_reserved', nextAction: 'Use original Owner intake; no keyword fallback.' };
|
|
771
|
+
}
|
|
772
|
+
if (!assessWorkbuddyLiveKeyword(prompt, sessionId).matched) {
|
|
773
|
+
return { ok: true, outcomes: [] };
|
|
774
|
+
}
|
|
775
|
+
const nativeIdentity = JSON.stringify(['workbuddy', sessionId, generationId]);
|
|
776
|
+
return admitGovernanceSignalsInternal({
|
|
777
|
+
workspaceDir: input.workspaceDir,
|
|
778
|
+
candidates: [{
|
|
779
|
+
kind: 'user_correction',
|
|
780
|
+
hostKind: 'workbuddy',
|
|
781
|
+
logicalObservationKey: nativeIdentity + '|user',
|
|
782
|
+
rolloutIdentity: JSON.stringify(['workbuddy', sessionId]),
|
|
783
|
+
rootSessionId: sessionId,
|
|
784
|
+
hostTurnId: nativeIdentity,
|
|
785
|
+
text: prompt,
|
|
786
|
+
observedAt: (input.now ?? new Date()).toISOString(),
|
|
787
|
+
}],
|
|
788
|
+
keywordStore: workbuddyP0KeywordStore(),
|
|
789
|
+
...(input.now ? { now: input.now } : {}),
|
|
790
|
+
...(input.databaseFactory ? { databaseFactory: input.databaseFactory } : {}),
|
|
791
|
+
}, true);
|
|
792
|
+
}
|
|
693
793
|
// ─── Diagnostician continuation (one pain → exactly one pending task) ───────
|
|
694
794
|
function isGovernanceTaskPayload(value) {
|
|
695
795
|
if (!isRecord(value))
|
|
@@ -87,5 +87,6 @@ export declare function createProductionHostRuntime(options?: Partial<Pick<HostR
|
|
|
87
87
|
}): HostRuntime;
|
|
88
88
|
export * from './behavior-example-pack-assembler.js';
|
|
89
89
|
export * from './behavior-history.js';
|
|
90
|
-
export * from './
|
|
90
|
+
export * from './codex-rule-context-provider.js';
|
|
91
|
+
export { createWorkspaceBehaviorEvidencePort } from './workspace-behavior-evidence.js';
|
|
91
92
|
export * from './explicit-owner-statement-prefix.js';
|
|
@@ -181,6 +181,7 @@ export function createHostRuntime(options) {
|
|
|
181
181
|
}
|
|
182
182
|
export function createProductionHostRuntime(options = {}) {
|
|
183
183
|
const productionGate = createProductionRuleHostGate({
|
|
184
|
+
...(options.hostKind ? { hostKind: options.hostKind } : {}),
|
|
184
185
|
...(options.projectDir ? { projectDir: options.projectDir } : {}),
|
|
185
186
|
...(options.ruleContextProvider ? { ruleContextProvider: options.ruleContextProvider } : {}),
|
|
186
187
|
...(options.ruleInputEnrichmentProvider ? { ruleInputEnrichmentProvider: options.ruleInputEnrichmentProvider } : {}),
|
|
@@ -192,6 +193,7 @@ export function createProductionHostRuntime(options = {}) {
|
|
|
192
193
|
...(options.painEnrichmentProvider ? { painEnrichmentProvider: options.painEnrichmentProvider } : {}),
|
|
193
194
|
...(options.painDatabaseFactory ? { painDatabaseFactory: options.painDatabaseFactory } : {}),
|
|
194
195
|
...(options.hostKind ? { hostKind: options.hostKind } : {}),
|
|
196
|
+
...(options.projectDir ? { projectDir: options.projectDir } : {}),
|
|
195
197
|
...(options.events ? { events: options.events } : {}),
|
|
196
198
|
}),
|
|
197
199
|
beforeToolCall: options.beforeToolCall ?? productionGate,
|
|
@@ -267,5 +269,6 @@ export function createProductionHostRuntime(options = {}) {
|
|
|
267
269
|
}
|
|
268
270
|
export * from './behavior-example-pack-assembler.js';
|
|
269
271
|
export * from './behavior-history.js';
|
|
270
|
-
export * from './
|
|
272
|
+
export * from './codex-rule-context-provider.js';
|
|
273
|
+
export { createWorkspaceBehaviorEvidencePort } from './workspace-behavior-evidence.js';
|
|
271
274
|
export * from './explicit-owner-statement-prefix.js';
|
|
@@ -693,7 +693,7 @@ export async function runInternalizationConsumerCycle(workspaceDir, ports) {
|
|
|
693
693
|
break;
|
|
694
694
|
case 'scribe':
|
|
695
695
|
runner = new ScribeRunner({
|
|
696
|
-
stateManager, runtimeAdapter: adapter, eventEmitter: storeEmitter, artifactStore: stateManager.piArtifactStore, validator: new DefaultScribeValidator(),
|
|
696
|
+
stateManager, runtimeAdapter: adapter, eventEmitter: storeEmitter, artifactStore: stateManager.piArtifactStore, validator: new DefaultScribeValidator({ requireRuleCodeContracts: true }),
|
|
697
697
|
// I2 — CHAIN STAMPING (Owner review of PR #1856, P1): the scribe
|
|
698
698
|
// stamps the ledger principle UUID (minted at intake, keyed by the
|
|
699
699
|
// dreamer task seed's candidateId) onto the artifact it writes, so
|
|
@@ -170,6 +170,9 @@ export function createEvaluatorRepairDeps(workspaceDir, stateManager, logger) {
|
|
|
170
170
|
timeoutMs: params.inheritedTimeoutMs,
|
|
171
171
|
inputArtifactRefs: [...params.inheritedInputArtifactRefs],
|
|
172
172
|
outputArtifactRefs: [],
|
|
173
|
+
...(params.ownerEvidenceSelection !== undefined
|
|
174
|
+
? { ownerEvidenceSelection: params.ownerEvidenceSelection }
|
|
175
|
+
: {}),
|
|
173
176
|
repairPayload: params.repairPayload,
|
|
174
177
|
}),
|
|
175
178
|
});
|
|
@@ -143,6 +143,7 @@ export declare function createProductionPainEvidenceHandler(options?: {
|
|
|
143
143
|
painEnrichmentProvider?: PainEnrichmentProvider;
|
|
144
144
|
painDatabaseFactory?: PainDatabaseFactory;
|
|
145
145
|
hostKind?: GovernanceHostKind;
|
|
146
|
+
projectDir?: string;
|
|
146
147
|
events?: HostEventEmitter;
|
|
147
148
|
}): (event: HostEvent) => Promise<HostEventResult>;
|
|
148
149
|
export declare function resetProductionPainCooldownForTest(): void;
|
|
@@ -225,7 +225,7 @@ export function deriveProductionCorrectionPainIdentity(fields) {
|
|
|
225
225
|
}
|
|
226
226
|
const REQUIRED_COLUMNS = {
|
|
227
227
|
sessions: { session_id: 'TEXT', started_at: 'TEXT', updated_at: 'TEXT' },
|
|
228
|
-
tool_calls: { session_id: 'TEXT', tool_name: 'TEXT', outcome: 'TEXT', duration_ms: 'INTEGER', exit_code: 'INTEGER', error_type: 'TEXT', error_message: 'TEXT', gfi_before: 'REAL', gfi_after: 'REAL', params_json: 'TEXT', result_preview: 'TEXT', created_at: 'TEXT' },
|
|
228
|
+
tool_calls: { session_id: 'TEXT', tool_name: 'TEXT', outcome: 'TEXT', duration_ms: 'INTEGER', exit_code: 'INTEGER', error_type: 'TEXT', error_message: 'TEXT', gfi_before: 'REAL', gfi_after: 'REAL', params_json: 'TEXT', result_preview: 'TEXT', created_at: 'TEXT', project_dir: 'TEXT' },
|
|
229
229
|
pain_events: { session_id: 'TEXT', source: 'TEXT', score: 'REAL', reason: 'TEXT', severity: 'TEXT', origin: 'TEXT', confidence: 'REAL', text: 'TEXT', canonical_pain_id: 'TEXT', runtime_task_id: 'TEXT', host_kind: 'TEXT', created_at: 'TEXT' },
|
|
230
230
|
};
|
|
231
231
|
function pragmaField(row, key) {
|
|
@@ -277,7 +277,7 @@ function hasCanonicalSchema(db) {
|
|
|
277
277
|
db.prepare('SELECT 1 FROM tool_calls WHERE session_id = ? AND tool_name = ? AND params_json = ? AND outcome = ? AND exit_code IS ? AND error_message IS ? AND result_preview IS ?');
|
|
278
278
|
db.prepare('SELECT 1 FROM pain_events WHERE canonical_pain_id = ?');
|
|
279
279
|
db.prepare('INSERT INTO sessions (session_id, started_at, updated_at) VALUES (?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET updated_at = excluded.updated_at');
|
|
280
|
-
db.prepare('INSERT INTO tool_calls (session_id, tool_name, outcome, duration_ms, exit_code, error_type, error_message, gfi_before, gfi_after, params_json, result_preview, created_at, tool_use_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
|
|
280
|
+
db.prepare('INSERT INTO tool_calls (session_id, tool_name, outcome, duration_ms, exit_code, error_type, error_message, gfi_before, gfi_after, params_json, result_preview, created_at, tool_use_id, project_dir) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
|
|
281
281
|
db.prepare('INSERT INTO pain_events (session_id, source, score, reason, severity, origin, confidence, text, canonical_pain_id, runtime_task_id, host_kind, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)');
|
|
282
282
|
return true;
|
|
283
283
|
}
|
|
@@ -301,6 +301,19 @@ function ensureToolCallsToolUseIdColumn(db) {
|
|
|
301
301
|
// the prepared-statement readiness check below fails loud if it is truly absent.
|
|
302
302
|
}
|
|
303
303
|
}
|
|
304
|
+
/** Additive migration for verified host cwd binding; legacy rows stay NULL. */
|
|
305
|
+
function ensureToolCallsProjectDirColumn(db) {
|
|
306
|
+
const columns = db.prepare('PRAGMA table_info(tool_calls)').all();
|
|
307
|
+
if (columns.some((row) => pragmaField(row, 'name') === 'project_dir'))
|
|
308
|
+
return;
|
|
309
|
+
try {
|
|
310
|
+
db.exec('ALTER TABLE tool_calls ADD COLUMN project_dir TEXT');
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
// A concurrent writer may have added it between the check and the ALTER;
|
|
314
|
+
// the prepared-statement readiness check below fails loud if absent.
|
|
315
|
+
}
|
|
316
|
+
}
|
|
304
317
|
/**
|
|
305
318
|
* SPEC-CODEX-PAIN-CLOSURE-001 CR-01: upgrade the live-hook observation of a
|
|
306
319
|
* tool call with the host-verified final result (exit code) read through the
|
|
@@ -412,6 +425,7 @@ export function createProductionPainEvidenceHandler(options = {}) {
|
|
|
412
425
|
db = options.painDatabaseFactory ? options.painDatabaseFactory(dbPath) : new Database(dbPath);
|
|
413
426
|
db.pragma('busy_timeout = 5000');
|
|
414
427
|
ensureToolCallsToolUseIdColumn(db);
|
|
428
|
+
ensureToolCallsProjectDirColumn(db);
|
|
415
429
|
if (!hasCanonicalSchema(db)) {
|
|
416
430
|
db.close();
|
|
417
431
|
db = undefined;
|
|
@@ -518,8 +532,8 @@ export function createProductionPainEvidenceHandler(options = {}) {
|
|
|
518
532
|
return;
|
|
519
533
|
}
|
|
520
534
|
db.prepare(`INSERT INTO sessions (session_id, started_at, updated_at) VALUES (?, ?, ?) ON CONFLICT(session_id) DO UPDATE SET updated_at = excluded.updated_at`).run(event.context.sessionId, createdAt, createdAt);
|
|
521
|
-
db.prepare(`INSERT INTO tool_calls (session_id, tool_name, outcome, duration_ms, exit_code, error_type, error_message, gfi_before, gfi_after, params_json, result_preview, created_at, tool_use_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
522
|
-
.run(event.context.sessionId, toolName, outcome.outcome, outcome.durationMs ?? null, outcome.exitCode, outcome.error ? outcome.error.split(/[\s:]/, 1)[0] : null, outcome.error ?? null, null, null, paramsJson, resultPreview, createdAt, event.context.toolCallId ?? null);
|
|
535
|
+
db.prepare(`INSERT INTO tool_calls (session_id, tool_name, outcome, duration_ms, exit_code, error_type, error_message, gfi_before, gfi_after, params_json, result_preview, created_at, tool_use_id, project_dir) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`)
|
|
536
|
+
.run(event.context.sessionId, toolName, outcome.outcome, outcome.durationMs ?? null, outcome.exitCode, outcome.error ? outcome.error.split(/[\s:]/, 1)[0] : null, outcome.error ?? null, null, null, paramsJson, resultPreview, createdAt, event.context.toolCallId ?? null, path.resolve(options.projectDir ?? event.context.workspaceDir));
|
|
523
537
|
if (admitted) {
|
|
524
538
|
// Raw observation only (Pain Diagnosis Persistence SPEC §8): the
|
|
525
539
|
// pain row must record WHAT happened, not WHY. Attribution
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ToolSemanticRegistry } from '@principles/core/runtime-v2';
|
|
1
|
+
import { type ToolSemanticRegistry, type GovernanceHostKind } from '@principles/core/runtime-v2';
|
|
2
2
|
import type { HostEvent, HostEventResult } from '@principles/core/host';
|
|
3
3
|
import { type RuleImplementationRuntime } from './rule-implementation-runtime.js';
|
|
4
4
|
export interface ProductionRuleContextRequest {
|
|
@@ -17,6 +17,7 @@ export interface RuleInputEnrichment {
|
|
|
17
17
|
export type RuleInputEnrichmentProvider = (request: ProductionRuleContextRequest) => unknown | Promise<unknown>;
|
|
18
18
|
export interface ProductionRuleHostGateOptions {
|
|
19
19
|
projectDir?: string;
|
|
20
|
+
hostKind?: GovernanceHostKind;
|
|
20
21
|
ruleContextProvider?: RuleContextProvider;
|
|
21
22
|
ruleInputEnrichmentProvider?: RuleInputEnrichmentProvider;
|
|
22
23
|
implementationRuntime?: RuleImplementationRuntime;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { buildRuleHostAction, buildToolSemanticRegistry, deriveToolHintsFromCanonicalKind, estimateLineChanges, mergeDecisions, SqliteConnection, UNAVAILABLE_RULE_CONTEXT, validateRuleContextV2, validateRuleHostResult, verifyPiArtifactRowDigest, } from '@principles/core/runtime-v2';
|
|
4
|
+
import { isSensitiveSystemPath } from '@principles/core/runtime-v2/internalization/rule-host-input-builder';
|
|
4
5
|
import { scanRetiredContractSymbols } from './legacy-rule-contract-symbols.js';
|
|
5
6
|
import { recordDegradedEnforcement } from './degraded-enforcement-marker.js';
|
|
6
7
|
import { createNodeRuleImplementationRuntime, MAX_ACTIVE_RULES, RULE_BATCH_SOURCE_BYTES, RULE_SOURCE_BYTES, } from './rule-implementation-runtime.js';
|
|
@@ -174,6 +175,8 @@ export function createProductionRuleHostGate(options = {}) {
|
|
|
174
175
|
SELECT a.activation_id, a.artifact_id, a.target_ref, a.action,
|
|
175
176
|
c.enforcement, c.isolation_decision_id,
|
|
176
177
|
p.source_rule_id, p.source_principle_id,
|
|
178
|
+
EXISTS (SELECT 1 FROM approvals ap WHERE ap.artifact_id = a.artifact_id
|
|
179
|
+
AND ap.channel = 'code_tool_hook' AND ap.status = 'approved') AS owner_approved,
|
|
177
180
|
length(CAST(p.content_json AS BLOB)) AS content_bytes,
|
|
178
181
|
(SELECT d.artifact_digest FROM activation_decisions d
|
|
179
182
|
WHERE d.subject_kind = 'activation' AND d.activation_id = a.activation_id
|
|
@@ -232,8 +235,8 @@ export function createProductionRuleHostGate(options = {}) {
|
|
|
232
235
|
// through the SAME budget/content/context validation and
|
|
233
236
|
// evaluateBatch pipeline as live rows, but their results are
|
|
234
237
|
// collected as observations only and never join mergeDecisions
|
|
235
|
-
// (shadow observes, never enforces). The v2
|
|
236
|
-
//
|
|
238
|
+
// (shadow observes, never enforces). The v2 qualification and context
|
|
239
|
+
// checks below remain ahead of evaluation for both activation modes.
|
|
237
240
|
const activationMode = row.action === 'code_tool_hook_live_activate'
|
|
238
241
|
? 'live'
|
|
239
242
|
: row.action === 'code_tool_hook_shadow_activate' ? 'shadow' : null;
|
|
@@ -325,6 +328,42 @@ export function createProductionRuleHostGate(options = {}) {
|
|
|
325
328
|
addWarning(warnings, `unsupported_context_version: ${String(content.requiresContextVersion)}`, 'regenerate the rule artifact for context version 2');
|
|
326
329
|
continue;
|
|
327
330
|
}
|
|
331
|
+
// Codex V2 is opt-in per regenerated, Owner-approved artifact.
|
|
332
|
+
// This system-stamped contract is emitted only after current
|
|
333
|
+
// evaluator replay; merely wiring history must not revive old
|
|
334
|
+
// activations. Live execution additionally needs the existing
|
|
335
|
+
// promotion decision's binding to this exact artifact snapshot.
|
|
336
|
+
if (options.hostKind === 'codex') {
|
|
337
|
+
const contract = content.ruleHostInputContract;
|
|
338
|
+
const hosts = isRecord(contract) ? contract.hostKinds : undefined;
|
|
339
|
+
let contentBindingVerified = digestCheck.outcome === 'verified';
|
|
340
|
+
if (activationMode === 'shadow' && row.owner_approved === 1) {
|
|
341
|
+
// Old databases remain readable without writing a migration
|
|
342
|
+
// from this enforcement reader. A legacy approval without a
|
|
343
|
+
// content digest cannot grant Codex V2 execution eligibility.
|
|
344
|
+
const approvalColumns = connection.getDb().prepare('PRAGMA table_info(approvals)').all();
|
|
345
|
+
if (approvalColumns.some((column) => isRecord(column) && column.name === 'artifact_digest')) {
|
|
346
|
+
const approval = connection.getDb().prepare(`
|
|
347
|
+
SELECT artifact_digest FROM approvals
|
|
348
|
+
WHERE artifact_id = ? AND channel = 'code_tool_hook' AND status = 'approved'
|
|
349
|
+
ORDER BY decided_at DESC LIMIT 1
|
|
350
|
+
`).get(artifactId);
|
|
351
|
+
const approvalDigest = isRecord(approval) && typeof approval.artifact_digest === 'string'
|
|
352
|
+
? approval.artifact_digest : null;
|
|
353
|
+
contentBindingVerified = verifyPiArtifactRowDigest(contentRow, contentJson, approvalDigest).outcome === 'verified';
|
|
354
|
+
}
|
|
355
|
+
else {
|
|
356
|
+
contentBindingVerified = false;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
if (!isRecord(contract) || contract.version !== 1 || contract.contextVersion !== 2
|
|
360
|
+
|| !Array.isArray(hosts) || !hosts.every((host) => typeof host === 'string')
|
|
361
|
+
|| !hosts.includes('codex') || row.owner_approved !== 1
|
|
362
|
+
|| !contentBindingVerified) {
|
|
363
|
+
addWarning(warnings, `codex_rule_context_v2_unqualified: activation=${activationId}`, 'regenerate and replay this artifact for Codex, approve it for shadow observation, and use the existing Owner promotion flow for live execution');
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
328
367
|
// SPEC-RULECODE-QUALITY-001 A3 / §7.1 (Q10): MANDATORY runtime
|
|
329
368
|
// suspension of context-dependent rules. A v2 rule may only
|
|
330
369
|
// execute when the provider resolved a schema-valid context
|
|
@@ -379,7 +418,7 @@ export function createProductionRuleHostGate(options = {}) {
|
|
|
379
418
|
}
|
|
380
419
|
const hostInput = {
|
|
381
420
|
action,
|
|
382
|
-
workspace: { isRiskPath:
|
|
421
|
+
workspace: { isRiskPath: isSensitiveSystemPath(action.normalizedPath) },
|
|
383
422
|
session: { sessionId: event.context.sessionId, currentGfi: enrichment.currentGfi },
|
|
384
423
|
evolution: { epTier: enrichment.epTier },
|
|
385
424
|
derived: { estimatedLineChanges: estimateLineChanges({ toolName: input.toolName, params: input.params }), bashRisk: enrichment.bashRisk },
|
|
@@ -401,7 +440,9 @@ export function createProductionRuleHostGate(options = {}) {
|
|
|
401
440
|
if (remaining <= 0) {
|
|
402
441
|
return { decision: 'allow', source: event.source, warnings: [boundedWarning('gate_deadline_exceeded', 'reduce active RuleCode count or source size and retry')], metadata: { evaluatedLiveRules: 0 } };
|
|
403
442
|
}
|
|
404
|
-
const liveBatch =
|
|
443
|
+
const liveBatch = liveCandidates.length === 0
|
|
444
|
+
? { ok: true, results: [] }
|
|
445
|
+
: implementationRuntime.evaluateBatch(liveCandidates.map((candidate) => ({ source: candidate.source, filename: `activation-${candidate.implId}` })), hostInput, remaining);
|
|
405
446
|
if (!liveBatch.ok || !liveBatch.results) {
|
|
406
447
|
return { decision: 'allow', source: event.source, warnings: [boundedWarning(`${liveBatch.reason ?? 'rule_batch_failed'}: ${liveBatch.detail ?? 'unknown failure'}`, 'inspect active RuleCode resource use and repair or deactivate the unhealthy rule')], metadata: { evaluatedLiveRules: 0 } };
|
|
407
448
|
}
|
|
@@ -1,3 +1,21 @@
|
|
|
1
1
|
import type { BehaviorEvidencePort, ToolSemanticRegistry } from '@principles/core/runtime-v2';
|
|
2
|
+
import type { RuleHostContextRow } from '@principles/core/trajectory-types';
|
|
2
3
|
/** Lazy storage access: missing labels need no DB, and a failed open remains observable. */
|
|
3
4
|
export declare function createWorkspaceBehaviorEvidencePort(workspaceDir: string, toolSemantics?: ToolSemanticRegistry): BehaviorEvidencePort;
|
|
5
|
+
/**
|
|
6
|
+
* Read one bounded, same-session history window from the canonical trajectory
|
|
7
|
+
* database. The timestamp is the caller's pre-event cutoff; rows at or after
|
|
8
|
+
* it are excluded so replayed/future calls cannot enter a live RuleContext.
|
|
9
|
+
* This is read-only and never creates or migrates trajectory state.
|
|
10
|
+
*/
|
|
11
|
+
export declare function readWorkspaceRuleContextRowsBefore(workspaceDir: string, input: {
|
|
12
|
+
sessionId: string;
|
|
13
|
+
projectDir: string;
|
|
14
|
+
beforeCreatedAt: string;
|
|
15
|
+
excludeToolUseId: string;
|
|
16
|
+
limit: number;
|
|
17
|
+
}): {
|
|
18
|
+
rows: readonly RuleHostContextRow[];
|
|
19
|
+
truncated: boolean;
|
|
20
|
+
unscopedPriorRows: boolean;
|
|
21
|
+
};
|
|
@@ -72,3 +72,50 @@ export function createWorkspaceBehaviorEvidencePort(workspaceDir, toolSemantics)
|
|
|
72
72
|
},
|
|
73
73
|
};
|
|
74
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Read one bounded, same-session history window from the canonical trajectory
|
|
77
|
+
* database. The timestamp is the caller's pre-event cutoff; rows at or after
|
|
78
|
+
* it are excluded so replayed/future calls cannot enter a live RuleContext.
|
|
79
|
+
* This is read-only and never creates or migrates trajectory state.
|
|
80
|
+
*/
|
|
81
|
+
export function readWorkspaceRuleContextRowsBefore(workspaceDir, input) {
|
|
82
|
+
const { sessionId, projectDir, beforeCreatedAt, excludeToolUseId, limit } = input;
|
|
83
|
+
if (sessionId.trim().length === 0)
|
|
84
|
+
throw new Error('history_session_id_invalid');
|
|
85
|
+
if (!path.isAbsolute(projectDir))
|
|
86
|
+
throw new Error('history_project_dir_invalid');
|
|
87
|
+
if (excludeToolUseId.trim().length === 0)
|
|
88
|
+
throw new Error('history_tool_use_id_invalid');
|
|
89
|
+
if (!Number.isSafeInteger(limit) || limit < 1 || limit > 100)
|
|
90
|
+
throw new Error('history_limit_invalid');
|
|
91
|
+
if (!Number.isFinite(Date.parse(beforeCreatedAt)))
|
|
92
|
+
throw new Error('history_cutoff_invalid');
|
|
93
|
+
const db = new Database(path.join(workspaceDir, '.state', 'trajectory.db'), { readonly: true, fileMustExist: true });
|
|
94
|
+
try {
|
|
95
|
+
db.pragma('busy_timeout = 100');
|
|
96
|
+
return db.transaction(() => {
|
|
97
|
+
const rows = db.prepare(`
|
|
98
|
+
SELECT id, tool_name, outcome, params_json
|
|
99
|
+
FROM tool_calls
|
|
100
|
+
WHERE session_id = ? AND project_dir = ? AND created_at < ? AND (tool_use_id IS NULL OR tool_use_id <> ?)
|
|
101
|
+
ORDER BY created_at DESC, id DESC
|
|
102
|
+
LIMIT ?
|
|
103
|
+
`).all(sessionId, projectDir, beforeCreatedAt, excludeToolUseId, limit + 1);
|
|
104
|
+
const unscoped = db.prepare(`
|
|
105
|
+
SELECT 1 AS found FROM tool_calls
|
|
106
|
+
WHERE session_id = ? AND project_dir IS NULL AND created_at < ?
|
|
107
|
+
AND (tool_use_id IS NULL OR tool_use_id <> ?) LIMIT 1
|
|
108
|
+
`).get(sessionId, beforeCreatedAt, excludeToolUseId);
|
|
109
|
+
if (!Array.isArray(rows))
|
|
110
|
+
throw new Error('history_query_invalid');
|
|
111
|
+
return {
|
|
112
|
+
rows: rows.slice(0, limit).reverse().map(contextRow),
|
|
113
|
+
truncated: rows.length > limit,
|
|
114
|
+
unscopedPriorRows: unscoped !== undefined,
|
|
115
|
+
};
|
|
116
|
+
})();
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
db.close();
|
|
120
|
+
}
|
|
121
|
+
}
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-internalization-run-once.d.ts","sourceRoot":"","sources":["../../src/commands/runtime-internalization-run-once.ts"],"names":[],"mappings":"AA4CA,UAAU,cAAc;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"runtime-internalization-run-once.d.ts","sourceRoot":"","sources":["../../src/commands/runtime-internalization-run-once.ts"],"names":[],"mappings":"AA4CA,UAAU,cAAc;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkZD,wBAAsB,mCAAmC,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA4Y7F"}
|
|
@@ -166,7 +166,22 @@ function buildTestDoubleAdapter(runnerKind, taskId) {
|
|
|
166
166
|
});
|
|
167
167
|
}
|
|
168
168
|
if (runnerKind === 'scribe') {
|
|
169
|
+
let capturedSourcePhilosopherArtifactId = '';
|
|
169
170
|
return new TestDoubleRuntimeAdapter({
|
|
171
|
+
onStartRun: (input) => {
|
|
172
|
+
try {
|
|
173
|
+
const payloadStr = typeof input.inputPayload === 'string' ? input.inputPayload : JSON.stringify(input.inputPayload);
|
|
174
|
+
const parsed = JSON.parse(payloadStr);
|
|
175
|
+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
176
|
+
const sourceId = Reflect.get(parsed, 'sourcePhilosopherArtifactId');
|
|
177
|
+
if (typeof sourceId === 'string' && sourceId.trim() !== '') {
|
|
178
|
+
capturedSourcePhilosopherArtifactId = sourceId;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch { /* empty lineage fails the strict Scribe validator */ }
|
|
183
|
+
return { runId: `td-scribe-${Date.now()}`, runtimeKind: 'test-double', startedAt: new Date().toISOString() };
|
|
184
|
+
},
|
|
170
185
|
onPollRun: (_runId) => ({
|
|
171
186
|
runId: _runId,
|
|
172
187
|
status: 'succeeded',
|
|
@@ -177,17 +192,28 @@ function buildTestDoubleAdapter(runnerKind, taskId) {
|
|
|
177
192
|
runId: _runId,
|
|
178
193
|
payload: {
|
|
179
194
|
taskId,
|
|
180
|
-
sourcePhilosopherArtifactId:
|
|
195
|
+
sourcePhilosopherArtifactId: capturedSourcePhilosopherArtifactId,
|
|
181
196
|
principleDraft: {
|
|
182
197
|
title: 'Test Principle Draft',
|
|
183
|
-
statement: '
|
|
184
|
-
rationale: '
|
|
185
|
-
applicability: ['
|
|
186
|
-
antiPatterns: ['
|
|
198
|
+
statement: 'Before changing a system, verify the current requirement and affected behavior; do not act on unverified assumptions.',
|
|
199
|
+
rationale: 'Checking the stated requirement and affected behavior prevents avoidable changes based on assumptions.',
|
|
200
|
+
applicability: ['Changes to an existing system'],
|
|
201
|
+
antiPatterns: ['Making changes based only on an unverified assumption'],
|
|
187
202
|
confidence: 0.8,
|
|
188
203
|
},
|
|
204
|
+
intentContract: {
|
|
205
|
+
ownerIntent: 'Preserve the stated requirement while making changes.',
|
|
206
|
+
targetBehavior: 'Before changing a system, verify the current requirement and affected behavior.',
|
|
207
|
+
forbiddenBehavior: 'Do not make changes based only on an unverified assumption.',
|
|
208
|
+
evidenceSource: 'The source Philosopher principle draft and rationale.',
|
|
209
|
+
validationExpectation: 'The proposed change is checked against the stated requirement and affected behavior.',
|
|
210
|
+
},
|
|
211
|
+
// This fixture's principle requires no trusted external facts; the
|
|
212
|
+
// explicit empty declaration keeps the test double aligned with the
|
|
213
|
+
// strict new-generation contract without weakening production validation.
|
|
214
|
+
executionConditions: { version: 1, requiredFacts: [] },
|
|
189
215
|
sourceTrace: {
|
|
190
|
-
philosopherArtifactId:
|
|
216
|
+
philosopherArtifactId: capturedSourcePhilosopherArtifactId,
|
|
191
217
|
},
|
|
192
218
|
risks: [],
|
|
193
219
|
generatedAt: new Date().toISOString(),
|
|
@@ -517,7 +543,7 @@ export async function handleRuntimeInternalizationRunOnce(opts) {
|
|
|
517
543
|
runnerResult = await runner.run(wakeResult.taskId);
|
|
518
544
|
}
|
|
519
545
|
else if (runnerKind === 'scribe') {
|
|
520
|
-
const validator = new DefaultScribeValidator();
|
|
546
|
+
const validator = new DefaultScribeValidator({ requireRuleCodeContracts: true });
|
|
521
547
|
const runner = new ScribeRunner({
|
|
522
548
|
stateManager, runtimeAdapter, eventEmitter, validator, artifactStore,
|
|
523
549
|
// I2 — CHAIN STAMPING (Owner review of PR #1856, P1): stamp the
|