mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-15 20:55:28 +02:00
- questionIdsFor and condensedHintFor take an optional
{ externalContract: true }; without it a code change that handles data
asks data-schema only, and an unknown profile gets the original four
questions and condensed hint.
- The hook reads GATEGUARD_EXTERNAL_CONTRACT_QUESTION with the same
spellings as GATEGUARD_METRICS and passes it to the full denial, the
condensed denial and the metrics record, so all three agree.
- The effectiveness harness's arm patch forwards the option, so an arm
never drops it silently.
Docs: change-profile.md gains an External-contract question section and
qualifies "byte-identical to the fixed four questions"; design-notes.md,
SKILL.md (switch table, data rule, word-for-word set) and CHANGELOG say
the fifth question is opt-in; question-effectiveness.md and the harness
README note that the runner clears GATEGUARD_* variables, so a gate arm
from a current tree measures the gate without the question.
skill-triggers@1.json: registryDigest refreshed for the SKILL.md body
change; the description and triggers are unchanged.
63 lines
2.8 KiB
JavaScript
63 lines
2.8 KiB
JavaScript
'use strict';
|
|
|
|
// Copied next to each materialized hook tree; it must not require anything outside that tree.
|
|
// see docs/gateguard/question-effectiveness.md#arms
|
|
|
|
const PLACEBO_TEXT = Object.freeze({
|
|
'placebo-goal': 'Restate in one sentence what this change is meant to achieve',
|
|
'placebo-steps': 'Describe the steps you will take to make this change',
|
|
'placebo-assumptions': 'State any assumptions you are making about this change',
|
|
'placebo-done': 'Describe how you will know the change is complete'
|
|
});
|
|
|
|
const PLACEBO_PHRASES = Object.freeze({
|
|
'placebo-goal': 'the goal of the change',
|
|
'placebo-steps': 'your planned steps',
|
|
'placebo-assumptions': 'your assumptions',
|
|
'placebo-done': 'how you will know it is done'
|
|
});
|
|
|
|
const PLACEBO_IDS = Object.keys(PLACEBO_TEXT);
|
|
const KEPT_ID = 'quote-instruction';
|
|
const VERBATIM_PHRASE = "the user's verbatim instruction";
|
|
|
|
function joinPhrases(phrases) {
|
|
if (phrases.length <= 2) return phrases.join(' and ');
|
|
return `${phrases.slice(0, -1).join(', ')}, and ${phrases[phrases.length - 1]}`;
|
|
}
|
|
|
|
/** Question ids for an arm, given the ids the unmodified gate would ask. */
|
|
function armQuestionIds(arm, ids) {
|
|
if (arm.placebo) {
|
|
let next = 0;
|
|
return ids.map(id => (id === KEPT_ID ? id : PLACEBO_IDS[next++ % PLACEBO_IDS.length]));
|
|
}
|
|
const dropped = new Set(arm.drop || []);
|
|
return ids.filter(id => !dropped.has(id));
|
|
}
|
|
|
|
/** Replaces the question table lookups of a loaded gateguard-target-class module for one arm. */
|
|
function applyArm(arm, targetClass) {
|
|
if (!arm || (!arm.placebo && !(arm.drop && arm.drop.length))) return targetClass;
|
|
const originalIds = targetClass.questionIdsFor;
|
|
const originalText = targetClass.questionText;
|
|
const originalPhrase = targetClass.condensedQuestionPhrase;
|
|
const originalHint = targetClass.condensedHintFor;
|
|
const questionIdsFor = (cls, isWrite, profile, options) => armQuestionIds(arm, originalIds(cls, isWrite, profile, options));
|
|
const questionText = id => (Object.hasOwn(PLACEBO_TEXT, id) ? PLACEBO_TEXT[id] : originalText(id));
|
|
const phraseFor = id => {
|
|
if (Object.hasOwn(PLACEBO_PHRASES, id)) return PLACEBO_PHRASES[id];
|
|
if (id === KEPT_ID) return VERBATIM_PHRASE;
|
|
return originalPhrase(id) || originalText(id).replace(/ \(search the tree.*\)$/, '').replace(/^\w/, c => c.toLowerCase());
|
|
};
|
|
const condensedHintFor = (cls, isWrite, profile, options) => {
|
|
const ids = questionIdsFor(cls, isWrite, profile, options);
|
|
if (ids.join('\n') === originalIds(cls, isWrite, profile, options).join('\n')) return originalHint(cls, isWrite, profile, options);
|
|
return `briefly state ${joinPhrases(ids.map(phraseFor).filter(Boolean))}, then retry.`;
|
|
};
|
|
Object.assign(targetClass, { questionIdsFor, questionText, condensedHintFor });
|
|
return targetClass;
|
|
}
|
|
|
|
module.exports = { PLACEBO_TEXT, PLACEBO_PHRASES, armQuestionIds, applyArm };
|