FE-844: Elicitation gaps architecture#197
Conversation
PR SummaryMedium Risk Overview Migration Adds Reviewed by Cursor Bugbot for commit 74aa041. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Pull request overview
This PR remodels the former elicitation backlog into a typed elicitation_gaps obligation register, derives structural gap coverage at read time from the graph, and introduces an initial capability-readiness evaluator that can proceed, proceed with low epistemic confidence, or negotiate via an establishment offer.
Changes:
- Replace
elicitation_backlogschema/table/commands/queries withelicitation_gaps(typed predicate + disposition + importance, plus live-derived coverage/answered). - Add a
session/capability-readinessprojection + tests that gates capabilities over relevant grounding gaps without importing stored-grade symbols. - Update topology/docs/tests/migrations to reflect the new gaps register and observed shape ownership.
Reviewed changes
Copilot reviewed 23 out of 24 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| src/projections/session/capability-readiness.ts | Adds capability readiness evaluator over relevant elicitation gaps. |
| src/projections/session/capability-readiness.test.ts | Covers readiness outcomes + live presence-derived flip integration. |
| src/projections/README.md | Registers the new session projection and its invariants/tests. |
| src/graph/schema/kinds.ts | Adds GAP_DISPOSITIONS + GAP_PREDICATE_KINDS enums. |
| src/graph/schema/elicitation-gaps.ts | Introduces ElicitationGap + predicate/disposition types. |
| src/graph/schema/elicitation-backlog.ts | Deletes the obsolete backlog entry type definitions. |
| src/graph/README.md | Updates architecture docs to reference elicitation_gaps register + owner query. |
| src/graph/queries.ts | Implements getElicitationGaps and presence-based coverage derivation. |
| src/graph/queries.test.ts | Updates query tests to assert live presence-derived coverage behavior. |
| src/graph/observed-shapes-coverage.test.ts | Renames observed shape entry to elicitation_gaps. |
| src/graph/index.ts | Re-exports gaps schema/types + getElicitationGaps. |
| src/graph/command-executor.ts | Seeds gaps at spec creation; adds create + disposition commands; adds predicate validation. |
| src/graph/command-executor.test.ts | Updates executor tests for seeding, create, and disposition behavior. |
| src/graph/architecture.test.ts | Updates enum-taxonomy boundary checks for new gap enums. |
| src/db/schema.ts | Replaces elicitation_backlog table with elicitation_gaps columns/constraints. |
| src/db/row-schemas.ts | Updates drizzle-typebox row schema exports for elicitation gaps. |
| src/db/README.md | Documents the new elicitation_gaps register and derived-coverage semantics. |
| memory/SPEC.md | Updates readiness and elicitation semantics to center gaps + capability-readiness. |
| memory/PLAN.md | Promotes/records the remodel + follow-on frontiers and sequencing notes. |
| memory/cards/gaps-node-kind-reference--node-kind-reference.md | Adds an active scope card for the node-kind reference follow-on. |
| drizzle/meta/0003_snapshot.json | Updates migration snapshot to reflect elicitation_gaps. |
| drizzle/0003_outstanding_black_bird.sql | Updates migration SQL to create elicitation_gaps. |
| docs/README.md | Adds the elicitation question catalog to docs index. |
| docs/design/ELICITATION_QUESTIONS.md | Adds per-kind elicitation question priming catalog. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if (!VALID_GAP_PREDICATE_KINDS.includes(predicate.kind)) { | ||
| diagnostics.push({ field: 'predicate.kind', message: 'predicate kind is not valid' }); | ||
| return; | ||
| } | ||
|
|
||
| if (predicate.kind === 'presence') { | ||
| if (!Number.isInteger(predicate.minimum) || predicate.minimum < 1) { | ||
| diagnostics.push({ field: 'predicate.minimum', message: 'minimum must be a positive integer' }); | ||
| } | ||
| if (predicate.plane !== undefined && !isNodePlane(predicate.plane)) { | ||
| diagnostics.push({ field: 'predicate.plane', message: 'plane is not valid' }); | ||
| } | ||
| if (predicate.band !== undefined && !isReadinessBand(predicate.band)) { | ||
| diagnostics.push({ field: 'predicate.band', message: 'band is not valid' }); | ||
| } | ||
| if (predicate.nodeKind === undefined && predicate.band === undefined) { | ||
| diagnostics.push({ field: 'predicate', message: 'presence predicate needs nodeKind or band' }); | ||
| } | ||
| } | ||
| } |
| function deriveGapCoverage( | ||
| db: BrunchDb, | ||
| specId: number, | ||
| predicate: GapPredicate, | ||
| disposition: GapDisposition, | ||
| ): number { | ||
| if (disposition === 'not_applicable' || disposition === 'irrelevant' || disposition === 'answered') | ||
| return 1; | ||
| if (predicate.kind === 'presence') return derivePresenceCoverage(db, specId, predicate); | ||
| return 0; | ||
| } |
| function relevantGapRecords( | ||
| capability: CapabilityId, | ||
| gaps: readonly ElicitationGap[], | ||
| ): readonly ElicitationGap[] { | ||
| const relevantNames = CAPABILITY_RELEVANT_GAPS[capability]; | ||
| return relevantNames.map((name) => gaps.find((gap) => gap.name === name) ?? missingGap(name)); | ||
| } |
| const storedDisposition = row.disposition as GapDisposition; | ||
| const predicate = JSON.parse(row.predicate) as GapPredicate; | ||
| const coverage = deriveGapCoverage(db, row.spec_id, predicate, storedDisposition); |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit fc7d5d6. Configure here.
fc7d5d6 to
708c25d
Compare
b4186e2 to
25dc094
Compare
Replace the FE-823 question-instance / open|closed backlog with the D65-L typed coverage-obligation model: ElicitationGap carries name + rationale, the presence|field|coverage|manual predicate union, importance + derived coverage, and a disposition enum. Seed the 8-typology grounding catalog at createSpec, add createElicitationGap / setElicitationGapDisposition mutations through CommandExecutor, and derive presence coverage/answered live from the graph at read-back (anti-shadowing: no stored structural state). Regenerate migration + Drizzle snapshot; reconcile SPEC/PLAN and graph/db topology READMEs. field/coverage derivation and manual satisficiency remain downstream.
Introduce the D74-L gate (src/projections/session/capability-readiness.ts): an explicit capability -> relevant-gaps map and evaluateCapabilityReadiness returning proceed / proceed_low_epistemic / negotiate(EstablishmentOffer), driven by live gap coverage with no stored readiness grade. Read-only judgment; never refuses outright (I31-L). Coexists with the existing grade gating for now. Reconcile SPEC/PLAN and projections README. Deferred follow-ons (capability-readiness frontier): readiness-estimate projection, MIN_GRADE consumer rewire, stored-grade deletion, and chrome.phase/chatMode removal.
708c25d to
74aa041
Compare


Summary