fix: round 2 of the release review of 6.3.0
Round 2 (v6.2.0..0d044f6, BLOCK: 2 BLOCKER, 11 MAJOR, 1 MINOR), each fixed behind a test that failed first. - The git runner checks only words /bin/sh passes through unchanged (no quote, backslash, $, glob or brace) and refuses --output and its abbreviations: round 1's --output refusal was bypassed by quoting. - fieldPaths: backticked paths are kept as written, parentheses and all; in plain text every path-like word counts, and a parenthesised note does not. - plan-validator --steps-from reads the plan's ## Verification for an appended End-to-end step, and warns instead of failing under --soft. - regression-check prints progress_status, the value progress.json takes; /trekexecute copies it. - release-check: a plugin in a subdirectory is checked in its own directory, the suite is not run when a cheaper check already makes the answer exit 2, and a bad argument or a crash is exit 2. - Skill routing looks a skill up among skills only, and builds the corpus vectors once. - /trekexecute Phase 7.2 says plainly that remediation steps in the review template's own form stop with a re-plan; making them runnable is a later order (operator 2026-10-10). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
0d044f6b6f
commit
ed87cc668d
10 changed files with 263 additions and 70 deletions
|
|
@ -102,7 +102,10 @@ export function buildCorpus(entries) {
|
|||
const df = new Map();
|
||||
for (const tf of docs.values()) for (const term of tf.keys()) df.set(term, (df.get(term) || 0) + 1);
|
||||
const n = docs.size;
|
||||
return { docs, idf: (term) => Math.log(1 + n / (1 + (df.get(term) || 0))), entries };
|
||||
const idf = (term) => Math.log(1 + n / (1 + (df.get(term) || 0)));
|
||||
// The corpus never changes: its vectors are built once, not per prompt or pair.
|
||||
const vecs = new Map([...docs].map(([id, tf]) => [id, vec(tf, idf)]));
|
||||
return { docs, idf, vecs, entries };
|
||||
}
|
||||
|
||||
function vec(tf, idf) {
|
||||
|
|
@ -122,7 +125,7 @@ function cosine(a, b) {
|
|||
export function rank(prompt, corpus) {
|
||||
const pv = vec(termFreq(tokenize(prompt)), corpus.idf);
|
||||
const out = [];
|
||||
for (const [id, tf] of corpus.docs) out.push({ id, score: cosine(pv, vec(tf, corpus.idf)) });
|
||||
for (const [id, v] of corpus.vecs) out.push({ id, score: cosine(pv, v) });
|
||||
return out.sort((a, b) => b.score - a.score || a.id.localeCompare(b.id));
|
||||
}
|
||||
|
||||
|
|
@ -132,7 +135,7 @@ export function collisions(corpus, t = THRESHOLDS) {
|
|||
const out = [];
|
||||
for (let i = 0; i < ids.length; i++) {
|
||||
for (let j = i + 1; j < ids.length; j++) {
|
||||
const sim = cosine(vec(corpus.docs.get(ids[i]), corpus.idf), vec(corpus.docs.get(ids[j]), corpus.idf));
|
||||
const sim = cosine(corpus.vecs.get(ids[i]), corpus.vecs.get(ids[j]));
|
||||
if (sim >= t.COLLISION_ERROR) out.push({ a: ids[i], b: ids[j], sim, level: 'error' });
|
||||
else if (sim >= t.COLLISION_WARN) out.push({ a: ids[i], b: ids[j], sim, level: 'warn' });
|
||||
}
|
||||
|
|
@ -205,8 +208,11 @@ export function loadCases(root) {
|
|||
export function checkRouting(root, t = THRESHOLDS) {
|
||||
const entries = loadEntries(root);
|
||||
const corpus = buildCorpus(entries);
|
||||
const byName = new Map(entries.map((e) => [e.name, e]));
|
||||
const skills = entries.filter((e) => e.kind === 'skill');
|
||||
// A skill is looked up among skills only: an agent or command with the same
|
||||
// name must not take its place. An owner may be any kind; a skill wins a tie.
|
||||
const skillByName = new Map(skills.map((e) => [e.name, e]));
|
||||
const byName = new Map([...entries.filter((e) => e.kind !== 'skill'), ...skills].map((e) => [e.name, e]));
|
||||
const cases = loadCases(root);
|
||||
const errors = [];
|
||||
const warnings = [];
|
||||
|
|
@ -220,7 +226,7 @@ export function checkRouting(root, t = THRESHOLDS) {
|
|||
|
||||
for (const c of cases) {
|
||||
if (!c.from) errors.push({ code: 'ROUTING_CASE_NO_SOURCE', case: c.case, message: `${c.case}: tag the event the case came from (from=...)` });
|
||||
const self = c.skill && byName.get(c.skill);
|
||||
const self = c.skill && skillByName.get(c.skill);
|
||||
if (!self || self.kind !== 'skill') {
|
||||
errors.push({ code: 'ROUTING_UNKNOWN_SKILL', case: c.case, message: `${c.case}: skill=${c.skill} is not a skill in skills/` });
|
||||
continue;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue