feat(spec-phase): surface zero-classification edge-probe requirements as unclassified candidates (#1110) (#1117)

Edge-probe now surfaces a zero-classification requirement (non-empty prose, no
shape cue matched, no `shapes` override) as a single soft `unclassified — review
manually` candidate instead of silently dropping it — the exact blind spot the
probe exists to catch. Dismissible like any edge; the `shapes: []` opt-out stays
silent; `TAXONOMY` (the closed 8 categories) is unchanged. Under `--auto` the
candidate is left `unresolved`, never auto-`backstop` (a missing shape is not
evidence an edge exists).

Closes #1110
This commit is contained in:
Rezolv
2026-06-14 21:44:21 -04:00
committed by GitHub
parent 395fb519e7
commit 3556450b0d
9 changed files with 111 additions and 4 deletions

View File

@@ -104,8 +104,16 @@ export function applicableCategories(shapes: Shape[]): string[] {
* taxonomy; both verification tiers require a non-empty `resolution` (an explicit AC's text
* or a backstop note) so plan-phase has a criterion to lift.
*/
/**
* Pseudo-category for a requirement whose prose matched NO shape cue (#1110). It is a soft
* "review manually" signal, NOT a 9th taxonomy category: it stays out of `TAXONOMY` (the closed
* eight) and only joins `EDGE_VALIDATORS.categories` so `analyzeCoverage` accepts the item.
*/
export const UNCLASSIFIED_CATEGORY = 'unclassified';
const UNCLASSIFIED_PROBE = 'unclassified — review manually';
export const EDGE_VALIDATORS: Validators = {
categories: TAXONOMY.map((c) => c.id),
categories: [...TAXONOMY.map((c) => c.id), UNCLASSIFIED_CATEGORY],
verification: ['explicit', 'backstop'],
requiredFieldsByVerification: { explicit: ['resolution'], backstop: ['resolution'] },
};
@@ -162,6 +170,22 @@ export function proposeEdges(requirement: Requirement): Edge[] {
shapes = requirement.shapes;
} else {
shapes = classifyShape(requirement.text);
if (shapes.length === 0) {
// Prose present but no shape cue matched. Do NOT silently drop it (#1110): an
// edge-relevant requirement whose phrasing missed every cue would otherwise vanish from
// coverage with no signal — the exact blind spot this probe exists to catch. Surface ONE
// soft, dismissible "unclassified — review manually" candidate. The explicit `shapes: []`
// opt-out (handled above) stays silent — that is the author's deliberate "no edge surface".
return [{
requirement_id: requirement.id,
category: UNCLASSIFIED_CATEGORY,
status: 'unresolved',
verification: null,
resolution: null,
reason: null,
probe: UNCLASSIFIED_PROBE,
}];
}
}
return applicableCategories(shapes).map((catId): Edge => {
const cat = TAXONOMY.find((c) => c.id === catId);