05 — Q3.8 + Q4.6.Q8 investigation — Bid response → corpus feedback loop (3 UC mapping)
05 — Q3.8 + Q4.6.Q8 investigation — Bid response → corpus feedback loop (3 UC mapping)
Section titled “05 — Q3.8 + Q4.6.Q8 investigation — Bid response → corpus feedback loop (3 UC mapping)”Status: Findings (S233 Wave 1B-4). Foreground investigation per feedback doc §1 lines 39-42. Q3.8 reframed from PENDING-ARCH → RESOLVED-DIRECTION after this finding.
Couples to: 1B-1 source_documents (binary-source manifest for prior-bid-response uploads), 1B-2 Q&A write-back + bid_question_matches (drafting loop consumer + match cache), 1B-3 historical extraction + coverage (bid_response as 4th coverage gap source), 1B-5 workspace types (bid is a workspace type; outcome JSONB column promotion question).
Audit date: 12/05/2026
Branch: content-items-investigation
Method: schema introspection (bid_questions, bid_responses, bid_response_history, workspaces.domain_metadata) + live prod row counts + tracing of lib/bid/bid-state-machine.ts, app/api/bids/[id]/{questions/extract,questions/match,responses/draft-all,outcome,outcome/integrate}/route.ts, lib/validation/schemas.ts (BidMetadataSchema, KBIntegrationBodySchema, BidOutcomeBodySchema).
1. TL;DR
Section titled “1. TL;DR”- All three UCs are partially or fully designed; the architecture is largely in place. Two of the three feedback-loop directions are wired today (UC-B in-platform bid creation; UC-C outcome capture + integrate-to-KB). The third (UC-A external prior-bid-response import) has no first-class path — closest existing surface is
/api/uploadlanding DOCX ascontent_items(content_type='q_a_pair') via Pattern A/B detection, which loses bid-context provenance. Q3.8 resolves to RESOLVED-DIRECTION with three follow-up tasks (one per UC), not RESOLVED-COMPLETE. - UC-B (client creates response in platform) is the platform’s happy path — 11-state bid state machine (
draft → questions_extracted → matching → drafting → in_review → ready_for_export → submitted → won|lost|withdrawn) with full edit-flow §6.5 UC5 promotion semantics. Drafting writesbid_responses; revisions append tobid_response_history. Schema-impact when 1B-2 lands:bid_responses.source_content_ids UUID[](inline citation array) ports to the newcitationstable (1B-2 Rec 3);bid_questions.matched_content_ids UUID[]ports tobid_question_matches(1B-2 Rec 4). Both deprecate-with-history-preserved per 1B-2. - UC-C (outcome → corpus) exists as
POST /api/bids/[id]/outcome/integrate— admin/editor-driven, won-bids-only, dedup-checked (checkExactDuplicatefromlib/dedup), per-response opt-in ({question_id, action: 'new_entry' | 'update_existing' | 'skip', target_content_id, content_type}). Three gaps: (i) lost/withdrawn bids carry zero learning today (no signal capture); (ii) writes tocontent_itemsnotq_a_pairs(because S16 q_a_pairs table doesn’t exist yet — migration follows S16); (iii)BidMetadataSchemaparks outcome+evidence in JSONB (16 fields includingoutcome,outcome_notes,outcome_recorded_at/by,tender_document_ids,deadline) — Liam’s S232 “lift JSONB to typed columns” framing applies. Schema-impact: promote 6-9 outcome columns from JSONB to typed columns onworkspacesOR introduce abid_workspacessatellite (per 1B-5 Shape B pattern). - UC-A (external prior bid response import) has no first-class path. Today: drop DOCX into
/api/upload, Pattern A/B detects Q&A tables →content_itemswithcontent_type='q_a_pair'. Loses bid-context (which bid was this from? won/lost? what client?), loses confidence signal (was this response approved? what was the evaluator’s feedback?). New work needed (small): newcontent_items.ingest_sourcevalue'prior_bid_response'+prior_bid_metadata JSONB(client name + buyer + outcome-if-known + import date) OR — preferred — extension of the newq_a_extractionstable per S16 §6.3 withprior_bid_contexttyped columns. No new top-level table. - No new top-level table needed for Q3.8. All three UCs land on existing primitives (workspaces+bid_questions+bid_responses+bid_response_history+content_items / q_a_pairs / q_a_extractions / citations / bid_question_matches) plus targeted column additions. The 1B-2 changes (citations + bid_question_matches) ARE the schema upgrades that the bid feedback loop needs.
2. Live state — feedback-loop surfaces (12/05/2026)
Section titled “2. Live state — feedback-loop surfaces (12/05/2026)”2.1 Schema map (workspaces + bid descendants)
Section titled “2.1 Schema map (workspaces + bid descendants)”workspaces (4 prod rows, ALL type='intelligence', 0 bid rows)├── domain_metadata JSONB (BidMetadataSchema — 16 fields when type='bid')│ ├── buyer, status, deadline, reference_number, estimated_value│ ├── tender_source, tender_document_ids[], submission_date│ ├── outcome (won|lost|withdrawn|null), outcome_notes,│ │ outcome_recorded_at, outcome_recorded_by│ └── notes│└── bid_questions (0 prod rows; FK project_id → workspaces — renames to workspace_id per 1B-5) ├── question_text, section_name, section_sequence, question_sequence ├── word_limit, evaluation_weight, confidence_posture ├── matched_content_ids UUID[] (inline cache — ports to bid_question_matches per 1B-2) ├── template_requirement_id (FK → template_requirements) ├── status, has_variants, assigned_to │ └── bid_responses (0 prod rows; FK question_id → bid_questions) ├── response_text, response_text_advanced ├── source_content_ids UUID[] (inline citations — ports to citations per 1B-2 Rec 3) ├── review_status, drafted_by, last_edited_by, approved_by ├── overall_score numeric ├── version │ └── bid_response_history (0 prod rows; FK response_id → bid_responses) ├── version, response_text, response_text_advanced ├── source_content_ids UUID[] ├── review_status, edited_by, change_reason2.2 API routes — feedback-loop relevant
Section titled “2.2 API routes — feedback-loop relevant”| Route | Method | Purpose | Touches |
|---|---|---|---|
/api/bids/[id]/questions/extract | POST | Tender PDF/DOCX → bid_questions rows | lib/ai/extract-questions.ts (Anthropic tool-use); extractPDFQuestions / extractDOCXQuestions / extractTenderMetadata |
/api/bids/[id]/questions/match | POST | Match each bid_question against KB → matched_content_ids[] | Inline array cache (1B-2 ports to bid_question_matches) |
/api/bids/[id]/responses/draft | POST | Single-question 3-pass draft (Sonnet analysis / Opus drafting / Haiku quality) | bid_responses (new version row) |
/api/bids/[id]/responses/draft-all | POST | Batch-draft all questions | Multiple bid_responses writes |
/api/bids/[id]/responses/draft-stream | POST | Streamed draft (SSE) | Same |
/api/bids/[id]/responses/[rId] | PATCH | User-edits a draft | bid_responses updated + bid_response_history versioned |
/api/bids/[id]/responses/[rId]/regenerate | POST | Re-run drafting on a single response | Same |
/api/bids/[id]/responses/[rId]/restore | POST | Revert to a prior bid_response_history row | Same |
/api/bids/[id]/responses/estimate | POST | Cost estimation pre-draft-all | lib/coverage/cost-estimation.ts |
/api/bids/[id]/export/docx | GET | Export submission-ready DOCX | lib/bid/bid-export-docx.ts |
/api/bids/[id]/export/xlsx | GET | Export XLSX summary | lib/bid/bid-export-xlsx.ts |
/api/bids/[id]/outcome | POST | Record won/lost/withdrawn → workspaces.status + JSONB | BidOutcomeBodySchema; state-machine transition guard |
/api/bids/[id]/outcome/integrate | POST | Promote won-bid responses to KB. Per-response selection (action: 'new_entry' / 'update_existing' / 'skip'); 5 target content_types (q_a_pair / case_study / policy / methodology / capability). | KBIntegrationBodySchema; checkExactDuplicate; writes content_items |
/api/bids/[id]/tender | GET/POST/DELETE | Tender doc upload + replace | workspaces.domain_metadata.tender_document_ids[] |
/api/bids/[id]/templates/* | various | Template selection + auto-map + fill | Uses template_requirements from 1B-3 |
2.3 Bid state machine (today)
Section titled “2.3 Bid state machine (today)”Per lib/bid/bid-state-machine.ts:48-58:
draft ─┬─ questions_extracted ── matching ── drafting ── in_review ── ready_for_export ── submitted ─┬─ won │ ├─ lost └─ withdrawn (from any state) └─ withdrawnwon/lost/withdrawnare terminal. No transitions out.outcome/integrateroute gates onstatus === 'won'. Lost / withdrawn bids cannot integrate today.
3. UC-A — Client supplies prior bid responses in various formats
Section titled “3. UC-A — Client supplies prior bid responses in various formats”3.1 Today’s state
Section titled “3.1 Today’s state”No first-class path. Three indirect options exist:
| Path | What happens | Where provenance lands |
|---|---|---|
/api/upload route (DOCX) | Mammoth → HTML → lib/quality/qa-detection.ts Pattern A/B/C → content_items rows with content_type='q_a_pair' | content_items.ingest_source='manual'; bid-context entirely lost |
Python pipeline (scripts/kb_pipeline/) | Same fork — DOCX → markdown → classify → content_items | Same |
| Manual Q&A pair authoring | User types pairs into the Q&A editor | content_items with ingest_source='manual'; no bid-context |
Implications:
- Prior responses become indistinguishable from authored Q&A pairs once landed.
- Outcome / evaluator-feedback information from the source bid is dropped.
- Confidence signal is identical to fresh manual authoring (no “validated-by-winning-bid” boost).
- Cross-client provenance (this came from Client X’s bid for Buyer Y, response approved on date Z) is unrecoverable from the row.
3.2 Forward path (RECOMMENDED)
Section titled “3.2 Forward path (RECOMMENDED)”Two parallel work-streams, both small.
(i) New ingest source classification — content_items.ingest_source (or post-S16, q_a_extractions.extractor_kind) gets a new value 'prior_bid_response'. The upload route accepts a new optional body field {prior_bid: { client_name?, buyer?, outcome?, source_bid_date?, evaluator_notes? }} that lands in the typed columns (post-S16) or in metadata JSONB (pre-S16). One new ingest path, zero new tables.
(ii) Confidence-signal boost from prior outcome — q_a_pairs.confidence (per S16 §6.2) reads the prior-bid outcome at promotion time: won → confidence bonus; lost → confidence penalty; withdrawn → neutral. Surfaces in coverage’s tier scoring (1B-3 §4.3 — bid_response as 4th gap source).
Both changes are additive — no migration of existing rows required.
3.3 Schema impact
Section titled “3.3 Schema impact”| Change | Where | Notes |
|---|---|---|
New 'prior_bid_response' value in ingest-source / extractor-kind enum | content_items.ingest_source (pre-S16) OR q_a_extractions.extractor_kind (post-S16) | Single enum extension |
New typed columns prior_bid_client, prior_bid_buyer, prior_bid_outcome, prior_bid_date | q_a_extractions (post-S16) | 4 columns; only populated when extractor_kind = ‘prior_bid_response’ |
Upload-route field prior_bid_metadata (Zod-validated) | app/api/upload/route.ts + lib/validation/schemas.ts | New optional body field |
| Confidence-signal bonus rule | Promotion path in UC5 (per edit-flow §6.5) | App-side calculation; no schema |
4. UC-B — Client creates response in-platform with existing Q&A + new pairs
Section titled “4. UC-B — Client creates response in-platform with existing Q&A + new pairs”4.1 Today’s state (largely WORKING — per edit-flow §6.5)
Section titled “4.1 Today’s state (largely WORKING — per edit-flow §6.5)”The platform’s happy path. State sequence:
1. Workspace (type='bid') created with buyer + deadline metadata.2. Tender doc upload → /api/bids/[id]/tender — stored, tender_document_ids JSONB updated.3. /api/bids/[id]/questions/extract — Anthropic tool-use extraction from PDF/DOCX → bid_questions rows. State → questions_extracted.4. /api/bids/[id]/questions/match — match each question against KB → matched_content_ids[]. State → matching.5. /api/bids/[id]/responses/draft-all (or per-question drafts). 3-pass Sonnet+Opus+Haiku per cost-estimation.ts. Writes bid_responses + creates bid_response_history v1. State → drafting.6. User edits draft in TipTap editor → PATCH /responses/[rId] → bid_response_history v2..N. State → in_review when ready.7. Export DOCX/XLSX → /export/docx /export/xlsx. State → ready_for_export → submitted.8. POST /outcome → workspaces.status + domain_metadata.outcome. State → won|lost|withdrawn.Promotion of novel responses to Q&A pairs (UC5 per edit-flow §6.5): RATIFIED — user-initiated, never auto, draft → in_review (curator queue) → published. Not yet implemented as a discrete UI surface — the existing /outcome/integrate route is the closest primitive but is won-bid-only. UC5 broadens it to “promote at any point during drafting/review, not just at outcome”.
4.2 Gaps + schema-impact (1B-2 dependencies)
Section titled “4.2 Gaps + schema-impact (1B-2 dependencies)”| Today | After 1B-2 lands |
|---|---|
bid_questions.matched_content_ids UUID[] (inline cache) | bid_question_matches table (per 1B-2 Rec 4) — adds per-match score, match_method, recompute_run_id, rank_within_run. Drop inline column post-migration. |
bid_responses.source_content_ids UUID[] (inline citations) | Rows in citations table (per 1B-2 Rec 3 — renamed from content_citations). Add bid_response_id FK + chunk-level offsets. Drop inline array post-migration. |
bid_response_history.source_content_ids UUID[] (inline citations, per-version) | Tricky: citation history per response version. Recommendation: keep inline on bid_response_history (it’s a versioned snapshot) — only the live bid_responses row’s citations port to the new table. Re-evaluate at WP3 05-qa-flow.md. |
| No promotion-from-draft UI | UC5 surface — promote-to-Q&A button on each bid_response row → opens promotion dialog (scope_tag picker + intent vocabulary + duplicate-check). Per edit-flow §6.5.1 4.6.Q1-Q10. |
KB Integration Review (KBIntegrationReview) currently won-bid-only | Per 4.6.Q8: “Same surface as broader bid integration review” — extend to support pre-outcome promotion. |
4.3 Schema impact
Section titled “4.3 Schema impact”| Change | Where | Source |
|---|---|---|
bid_question_matches new table | 1B-2 Rec 4 | Already specced |
citations rename + extend (q_a_pair_id, chunk-level) | 1B-2 Rec 3 | Already specced |
| Promotion-from-draft UI | New components/bid/promote-response-to-qa-dialog.tsx | New work |
bid_responses.source_content_ids → citations.* migration | 1B-2 §10 sequence | Sequenced after citations rename |
bid_questions.matched_content_ids → bid_question_matches.* migration | 1B-2 §10 sequence | Sequenced after new table land |
Net: NO new tables for UC-B beyond what 1B-2 already proposed.
5. UC-C — Bid outcome feeds back as Q&A data informing future bids
Section titled “5. UC-C — Bid outcome feeds back as Q&A data informing future bids”5.1 Today’s state — /outcome/integrate route
Section titled “5.1 Today’s state — /outcome/integrate route”Active for won bids only (line 65 of route: if (bidStatus !== 'won') { return 400 }). Body schema (KBIntegrationBodySchema):
{ integrations: Array<{ question_id: UUID, action: 'new_entry' | 'update_existing' | 'skip', target_content_id?: UUID, // required if action='update_existing' title?: string, content_type?: 'q_a_pair' | 'case_study' | 'policy' | 'methodology' | 'capability' }>, skip_dedup?: boolean // admin-only; silent-ignored for non-admin}Flow:
- Admin/editor reviews
wonbid responses one-by-one. - Per response:
skip/update_existing(with content_id) /new_entry. checkExactDuplicateruns pre-insert; admin can override viaskip_dedup=true.new_entrywrites acontent_itemsrow with the chosencontent_type+ embedding generated vialib/ai/embed.ts.- Plain text extracted from response HTML via
htmlToPlainText.
5.2 Three gaps
Section titled “5.2 Three gaps”(i) Lost / withdrawn bids carry zero learning. State machine blocks transition out of lost/withdrawn; /outcome/integrate rejects non-won. Yet lost bids contain signal: which questions did we lack content for? Which responses scored low? Was there evaluator feedback? None captured today.
(ii) Writes to content_items, not q_a_pairs. Post-S16 q_a_pairs lands; integrate must update to target q_a_pairs (when content_type='q_a_pair') or content_items (other 4 types: case_study / policy / methodology / capability). Polymorphic target — route picks table based on content_type.
(iii) Outcome data in JSONB. workspaces.domain_metadata carries 16 fields when type='bid' (BidMetadataSchema): buyer / status / deadline / reference_number / estimated_value / tender_source / tender_document_ids[] / submission_date / outcome / outcome_notes / notes / outcome_recorded_at / outcome_recorded_by. Per Liam S232 “lift JSONB to typed columns” framing: at least 6 of these are first-class queryable values that should be typed columns (buyer, deadline, submission_date, outcome, outcome_recorded_at, outcome_recorded_by).
5.3 Forward path
Section titled “5.3 Forward path”For (i) — lost / withdrawn learning:
| Add | Where | Why |
|---|---|---|
bid_response.evaluator_score (numeric 0-100, nullable) | New column on bid_responses | Capture evaluator’s per-question score when available (often from debrief feedback) |
bid_response.evaluator_feedback (text, nullable) | New column on bid_responses | Free-text feedback per response from debrief |
bid_response_history.outcome_signal (text, nullable) | New column on bid_response_history | ”approved-pre-submission” / “approved-with-edits” / “rejected-by-internal-review” / “submitted-final” |
New outcome_signal_type enum value 'lost_bid_learning' (post-S16) | q_a_extractions.extractor_kind | When promoting a lost bid response to corpus, mark its provenance |
Route extension: /outcome/integrate accepts lost AND won bids (with different default actions) | app/api/bids/[id]/outcome/integrate/route.ts | Lost-bid promotion is a smaller use case (mostly “this question had no good answer — author one for next time”) but valuable signal |
For (ii) — q_a_pairs target post-S16:
| Change | Where |
|---|---|
/outcome/integrate route: when content_type='q_a_pair', write to q_a_pairs not content_items | app/api/bids/[id]/outcome/integrate/route.ts (post-S16 migration) |
KBIntegrationBodySchema: split content_type into target_table ∈ {q_a_pairs, content_items} + target_subtype ∈ {case_study, policy, …} | lib/validation/schemas.ts |
Citations write: through new citations table (1B-2) with q_a_pair_id or content_item_id depending on target | Same |
For (iii) — JSONB → typed columns:
Two options:
| Option | Shape | Pros | Cons |
|---|---|---|---|
A — promote 6-9 outcome columns to workspaces | Direct typed columns on workspaces: outcome, deadline, submission_date, outcome_recorded_at, outcome_recorded_by, buyer. Leave intelligence-specific fields in domain_metadata. | Simpler; queries against workspaces.outcome are direct. | workspaces becomes type-aware (columns only relevant when type=‘bid’). |
B — bid_workspaces satellite table (per 1B-5 Shape B pattern) | New table bid_workspaces (workspace_id PK FK → workspaces, buyer, deadline, outcome, ...) | Clean separation; matches 1B-5 satellite pattern; mirrors sales_proposals_workspaces future shape. | Joins required for every bid query. |
Recommendation: Option B for symmetry with 1B-5 Shape B per-type-satellite pattern. Sales proposals will need a proposal_workspaces table; competitor research a competitor_workspaces; etc. Bid is the precedent. Land in WP4 04-workspace-types.md.
5.4 Schema impact summary
Section titled “5.4 Schema impact summary”| Change | New | Modified | Source |
|---|---|---|---|
bid_workspaces satellite | new table | — | 1B-5 Shape B pattern; this finding |
bid_responses.evaluator_score (numeric) | — | new column | This finding |
bid_responses.evaluator_feedback (text) | — | new column | This finding |
bid_response_history.outcome_signal (text) | — | new column | This finding |
lost_bid_learning extractor_kind | enum extension | — | This finding |
/outcome/integrate route: accept lost + won; polymorphic target | — | route change | This finding |
q_a_pairs integration target (vs content_items) | — | route change | Coupled to S16 §10 sequence |
6. Recommendations (binding for downstream work)
Section titled “6. Recommendations (binding for downstream work)”- Q3.8 — Update decision-graph status from
PENDING-ARCH→RESOLVED-DIRECTION. Three UC-specific follow-ups carry forward as separate items (see Recs 2-4 below). Wire WP2 status sync (Wave 2 this session). - UC-A — New
'prior_bid_response'ingest path. Add asq_a_extractions.extractor_kindvalue (post-S16) + 4 typed prior-bid context columns. Touchpoint:app/api/upload/route.ts+lib/validation/schemas.ts. Small; lands alongside S16 migration sequence. - UC-B — Promotion-from-draft UI surface. Implement UC5 (per edit-flow §6.5.1) as a
promote-response-to-qa-dialog.tsxcomponent onbid_responsesrows. Uses 1B-2’s newcitations+bid_question_matchestables. Gates on S16q_a_pairs+ 1B-2 schema land. - UC-C — Lost-bid learning + JSONB-to-typed promotion. (a) Extend
/outcome/integrateroute to acceptlostANDwonbids with different default actions. (b) Addevaluator_score+evaluator_feedbackcolumns tobid_responses. (c) Addoutcome_signalcolumn tobid_response_history. (d) Promote 6-9 bid-specific JSONB fields to a newbid_workspacessatellite table (per 1B-5 Shape B pattern). All sequenced after S16q_a_pairslands. - Coverage 4th gap source
bid_response(per 1B-3 §4.3): wire intolib/coverage/gap-scoring.tspost-1B-2bid_question_matchesland. Connects UC-B and UC-C feedback loops back into platform-wide coverage signal. - No new top-level table for Q3.8 beyond what 1B-2 + this finding already propose. The bid-response feedback loop lands cleanly on existing primitives + 1B-1/1B-2/1B-5 schema upgrades.
7. Cross-coupling notes
Section titled “7. Cross-coupling notes”| Downstream item | Coupling |
|---|---|
| 1B-1 source_documents Option α/β | Prior-bid-response uploads (UC-A) ingest as DOCX/PDF binary sources. Under Option α: land in source_documents with mime_type + content_hash. Under Option β: cocoindex source-key. Same path as Phew Q&A library DOCXs today. |
| 1B-2 citations + bid_question_matches | UC-B drafting loop consumes bid_question_matches; UC-B citations write through new citations table. Both UC-B schema deps are 1B-2 deliverables. No additional 1B-2 work needed. |
| 1B-3 historical extraction + coverage | Coverage’s 4th bid_response gap source (1B-3 §4.3 Rec 4) consumes bid_question_matches rows. Feedback loop output (1B-3) is bid loop input (this finding). |
| 1B-5 workspace types + Q3.11 templates | UC-C JSONB-to-typed promotion creates bid_workspaces — the first satellite-table for the bid workspace type per 1B-5 Shape B. Establishes precedent for sales_proposals_workspaces, competitor_workspaces, training_workspaces. |
| S16 q_a_pairs + q_a_extractions | UC-A q_a_extractions.extractor_kind='prior_bid_response'; UC-C polymorphic integration target (q_a_pairs vs content_items). Both gate on S16 §10 migration land. |
| Edit-flow §6.5 UC5 promotion | RATIFIED. UC-B Rec 3 implements the UI surface. |
| Edit-flow §6.6 UC6 revision | When integrated Q&A pairs (from UC-C) need revision (e.g. regulatory update), UC6 user-direct flow applies. |
| WP3 architecture/08-new-features.md | Hosts: bid-feedback loop diagram (3 UCs); lost-bid learning capture; bid_workspaces satellite; outcome JSONB promotion. |
| WP3 architecture/04-workspace-types.md | Hosts: bid_workspaces as Shape B satellite precedent. |
| WP3 architecture/05-qa-flow.md | Hosts: promotion-from-draft (UC5) + promotion-from-outcome (UC-C) UI surfaces. |
8. Open questions raised
Section titled “8. Open questions raised”| Q | For |
|---|---|
| OQ-Q38-A | Lost-bid promotion default action — skip (current won-bid default for null actions) or new_entry with confidence penalty? Recommendation: skip (lost bids surface fewer high-value novel answers; opt-in only). |
| OQ-Q38-B | Evaluator feedback capture UX — free-text on /outcome form, or per-response inline in the review surface, or both? Recommendation: both (top-level outcome notes + per-response evaluator_feedback). |
| OQ-Q38-C | Citation provenance from bid_response_history — port versioned citations into citations (large rows) or keep inline source_content_ids[] on history (skewed read pattern)? Recommendation: keep inline on history; only current bid_responses row’s citations port to the new table. |
| OQ-Q38-D | Confidence-signal weighting for prior-bid-outcome — won → +0.1, lost → -0.05, withdrawn → 0? Floor at 0.0; cap at 1.0. Recommendation: calibrate post-launch; ship with conservative defaults. |
| OQ-Q38-E | bid_workspaces satellite column set — minimum 6 (buyer / deadline / submission_date / outcome / outcome_recorded_at / outcome_recorded_by) or extended to all 16 BidMetadataSchema fields? Recommendation: 6-column minimum; remaining 10 (reference_number, estimated_value, tender_source, tender_document_ids[], outcome_notes, notes) stay in JSONB. Promote only the queryable / RLS-relevant ones. |
| OQ-Q38-F | When UC-C integrates a response to q_a_pairs (post-S16), does the citation chain back to the original bid_response (provenance trace)? Recommendation: yes — q_a_pairs.provenance_source carries {kind: 'bid_response', bid_response_id, bid_workspace_id, integrated_at}. |
| OQ-Q38-G | State-machine extension — should won / lost exit to a new learning_captured state after /outcome/integrate completes? Recommendation: no; integration is asynchronous + per-response. Don’t lock state on it. Track via bid_response.integrated_at column instead. |
End of finding 05.