mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-16 05:05:30 +02:00
fix(context): require a name or trigger anchor for implicit admission
This commit is contained in:
@@ -52,7 +52,7 @@ A task input contains caller-assigned `sessionId`, `taskId`, positive integer `r
|
||||
}
|
||||
```
|
||||
|
||||
Auto uses explicit user IDs first, then a completed pinned decision, an unambiguous ranked match, one cited skill name, or admitted agent-proposed IDs. Ambiguous free text shortlists up to five candidates for a bounded proposal. Manual uses explicit IDs; suggest emits a proposal without bodies. `--load` returns selected UTF-8 instructions and declared required resources, capped at 32,000 bytes across at most eight skills. `--task-input -` accepts one UTF-8 JSON object on standard input, capped at 65,536 bytes. These byte caps are output and transport bounds, not native tokenizer results.
|
||||
Auto uses explicit user IDs first, then a completed pinned decision, an unambiguous ranked match anchored by a term in the skill name or curated triggers, one cited skill name, or admitted agent-proposed IDs. Ambiguous free text shortlists up to five candidates for a bounded proposal. Manual uses explicit IDs; suggest emits a proposal without bodies. `--load` returns selected UTF-8 instructions and declared required resources, capped at 32,000 bytes across at most eight skills. `--task-input -` accepts one UTF-8 JSON object on standard input, capped at 65,536 bytes. These byte caps are output and transport bounds, not native tokenizer results.
|
||||
|
||||
Save the returned `selection.receipt` as a separate JSON document to use `--previous receipt.json`. `--expected-digest` can bind a load to a prior selection digest. Source, trigger content, routing-policy version, profile, mode, exclusions, session, task revision, phase, and a digest of the query invalidate stale reuse. A pending proposal cannot be reused as a completed decision. Receipts are integrity checks for local operation, not an authorization signature.
|
||||
|
||||
|
||||
@@ -88,4 +88,13 @@ Current combined verification after recovery:
|
||||
- The default sandbox checkout's 5,000-path capture limit truncated a real Tier 1 install diff and failed closed. The reviewed ECC-029 sandbox implementation raises the bounded cap to 50,000, passes its 26-case boundary suite, and produced both final reports. The driver receipt binds its 51-file implementation digest `a84e09ab848b8cd05f33792c13734f7aabe16bfe16d50d8f8292eb5261a93c3a`.
|
||||
- No real AI outcome call ran because `CODEX_API_KEY` was absent. Host ChatGPT authentication was neither copied nor exposed to the disposable evaluator.
|
||||
|
||||
## Auto-admission anchor (routing policy v5)
|
||||
|
||||
The 77-prompt routing corpus from #2945 (52 direct, 25 paraphrased) found one wrong implicit load. "two services both think they own the same record" admitted `skill:santa-method` on four description-only words (`two`, `both`, `they`, `same`) with BM25 24.3 and a 1.94 margin, clearing every v4 bar.
|
||||
|
||||
- RED: the prompt and the corpus check fail against v4 (`skill:santa-method` loaded).
|
||||
- GREEN: auto admission and the tier-2 fallback also require one matched term in the skill name or curated triggers. Exact directive citations are unchanged.
|
||||
- Corpus result: zero loads outside the expected set; 19 implicit admissions become 17. The other dropped admission, `skill:cost-tracking`, now defers to the bounded proposal instead of loading.
|
||||
- The existing nine-query auto/agent corpus, fallback, launch, evaluation and retrieval suites pass unchanged.
|
||||
|
||||
These boundaries keep the shipped behavior distinct from the M1 release gate. Authenticated outcome observations, a complete Tier 2 disk diff, live-install migration, other-provider activation, whole-context token truth and release defaults remain unverified until their explicit prerequisites are available.
|
||||
|
||||
@@ -171,12 +171,14 @@ function searchRetrieval(index, query, { limit = 5 } = {}) {
|
||||
.slice(0, limit)
|
||||
.map(([document, score]) => {
|
||||
const matched = [...new Set(queryTokens)].filter(term => document.weighted.has(term));
|
||||
const anchorTerms = matched.filter(term => document.fields.name.includes(term) || document.fields.triggers.includes(term));
|
||||
const exact = anchored.has(document);
|
||||
return { id: document.entry.id, score: Math.round(score * 10000) / 10000, exact,
|
||||
exactAlias: exact ? anchored.get(document) : undefined,
|
||||
dense: Math.round((dense.get(document) || 0) * 10000) / 10000,
|
||||
bm25: Math.round((bm25.get(document) || 0) * 10000) / 10000,
|
||||
matchedTerms: matched,
|
||||
anchorTerms,
|
||||
description: document.entry.description.slice(0, 2048),
|
||||
descriptionTruncated: document.entry.description.length > 2048 };
|
||||
});
|
||||
|
||||
@@ -26,9 +26,14 @@ const AUTO_ADMIT_MARGIN = 1.5;
|
||||
const FALLBACK_MIN_BM25 = 12;
|
||||
const FALLBACK_MIN_TERMS = 2;
|
||||
const FALLBACK_MARGIN = 1.1;
|
||||
// Both tiers also require at least one matched term in the skill's name or
|
||||
// curated triggers. Description-only overlap on common words (two, both, same)
|
||||
// can clear the score bars without naming the skill's subject.
|
||||
const MIN_ANCHOR_TERMS = 1;
|
||||
// v4: an explicit empty proposal (decline) is honored; the tier-2 fallback no
|
||||
// longer overrides declines at the launch/selection call sites.
|
||||
const ROUTING_POLICY_VERSION = 4;
|
||||
// v5: implicit admission requires a name or trigger anchor term.
|
||||
const ROUTING_POLICY_VERSION = 5;
|
||||
const TASK_KEYS = new Set(['sessionId', 'taskId', 'revision', 'phase', 'query', 'explicitIds', 'proposedIds', 'noWorkflow']);
|
||||
|
||||
function validateTask(task) {
|
||||
@@ -210,6 +215,7 @@ function resolveTaskContext({ repoRoot = DEFAULT_REPO_ROOT, task, profileId = 'l
|
||||
const top = candidates[0];
|
||||
const second = candidates[1];
|
||||
if (top.bm25 >= AUTO_ADMIT_MIN_BM25 && top.matchedTerms.length >= AUTO_ADMIT_MIN_TERMS
|
||||
&& top.anchorTerms.length >= MIN_ANCHOR_TERMS
|
||||
&& (!second || top.bm25 >= AUTO_ADMIT_MARGIN * (second.bm25 || 0))) {
|
||||
autoSelection = { id: top.id, bm25: top.bm25, matchedTerms: top.matchedTerms.length, exact: false };
|
||||
}
|
||||
@@ -221,6 +227,7 @@ function resolveTaskContext({ repoRoot = DEFAULT_REPO_ROOT, task, profileId = 'l
|
||||
const top = candidates[0];
|
||||
const second = candidates[1];
|
||||
if (top.bm25 >= FALLBACK_MIN_BM25 && top.matchedTerms.length >= FALLBACK_MIN_TERMS
|
||||
&& top.anchorTerms.length >= MIN_ANCHOR_TERMS
|
||||
&& (!second || top.bm25 >= FALLBACK_MARGIN * (second.bm25 || 0))) {
|
||||
fallback = { id: top.id, bm25: top.bm25, matchedTerms: top.matchedTerms.length };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user