Retail RFP transmission system — v1 build spec #1

Open
opened 2026-08-02 03:05:50 +00:00 by christian · 0 comments
Owner

Destination

A v1 code layout committed to this repo: the directory and module structure, the domain model
as real schema files, the permission boundaries expressed as code, and the seams where the
undecided parts will land. Not a running product — the skeleton a build can start from without
being redesigned.

Everything on the map serves that. Which means the tickets that determine structure — schema,
tenancy, visibility, data release, vault, entitlement — gate the destination, while the ones that
determine behaviour — ranking internals, audit retention, kickoff scope, retailer integrations —
can land as modules with stubs and be resolved after the layout exists.

v1 is a demoable proof of concept. Amended after real completed vendor responses proved
unobtainable — the schema is designed against a synthesized response corpus written to
solicitations we genuinely hold. The RFP half rests on real artifacts; the response half does not.
Lightweight but with teeth: the corpus must stress the schema, not flatter it. Nothing built on this
schema should be treated as production-ready until at least one real completed response has tested
it. See Obtain real completed vendor responses.

The destination has been reached. The v1 code layout is committed - see
Assemble the v1 code layout. Every remaining ticket is behaviour landing in an existing
seam, v1 content filling a vocabulary the surfaces already render, or the demo chain. Nothing left
on this map redesigns the skeleton.

One demo artifact is in scope, by author direction. A clickable POC prototype for the
first internal meeting - the six surfaces styled and navigable over synthesized corpus data, with
no RLS, scheduler, extraction or billing behind them. It sits just past "not a running product" and
is admitted deliberately rather than by drift: it is a design artifact built from the same surfaces
and corpus the layout uses, not a first build. See
Build the clickable POC prototype for the internal demo. The code layout remains the
destination; the prototype is allowed to be throwaway.

Market validation is deliberately not part of this map. The map assumes demand and resolves
design. See Out of scope.

Notes

Domain. A two-sided RFP marketplace. Large retailers (Walmart/Target scale) distribute RFPs
and evaluate bids for free; revenue comes from a tiered vendor-workspace subscription. The free side
is the retailer; the paying side is the bidder.

There is no free vendor tier. Amended by author direction — a $100/month floor gates
participation entirely, with Pro at $350/mo and Enterprise at $1,000/mo. This reversed
What do bidders actually pay for? and decision 1 of entitlement; both carry
supersession notices. The cost is recorded rather than resolved: it puts the two sides in tension
by construction, and the supplier-diversity exposure is a retailer-side adoption risk. See
Specify the vendor pricing and tier structure.

This is a HelmDocs product. Settled by author direction: a sibling to the existing
bidder-tools product under one brand, not its own. The design system is therefore extended rather
than authored - packages/config/shadcn.css in novelpad-desktop already carries
data-brand="helmdocs" tokens. The cost is recorded rather than resolved: the venue now carries
the bidder-tools brand, so a retailer may reasonably ask why the company selling bid-writing AI runs
their evaluation. That argument can no longer be made by brand distance and must be made by
mechanism - sealed bidding, the human commit, the model bar - which makes those mechanisms
demo-critical. See the component system.

The central inversion. The artifact worth standardizing is the response, not the RFP. Bid
ranking works because responses are machine-comparable, not because RFPs are. So the paying side
produces the value the free side receives — the mirror of Ramp, where free software generates the
monetized asset.

Skills each session should consult. /grill-me for decision tickets. /to-issues once the
spec is locked. This repo has no /research, /prototype, or /domain-modeling skill installed —
substitute a general-purpose research subagent for research tickets and drive prototypes inline.

Standing preferences.

  • The existing bidder-side engine lives in the novelpad-desktop monorepo
    (packages/ai/src/agents/*, packages/core/src/solicitation-extraction/). Reuse the thinking
    and the prompts; v1 is a separate deployable, so do not reuse the runtime.
  • Standing architectural constraint (from the tenancy decision): isolation is enforced by
    Postgres row-level security, with actor context carried in transaction-scoped session GUCs.
    Every subsequent ticket must produce rules that are expressible in policy SQL, and the code
    layout must funnel all data access through one database entry point.
  • Standing guardrail (from the schema decision, reaffirmed by review): there is no cross-RFP
    score, no normalised rating, and no derived vendor win rate. Scores are raw and per-document.
    A win rate is a global rating in different clothes and leaks competitive outcomes across the
    two-party boundary the product is sold on.
  • Plan, don't do. Tickets resolve decisions; nothing here is a build slice.
  • Refer to tickets by name, never by bare number.

Decisions so far

  • Where does the transmission system get built? — Greenfield, server-authoritative. A new deployable for the retailer side and the transmission network. HelmDocs integrates later across an API/MCP boundary.

  • Is this the retailer's system of record, or a layer on their existing stack? — Distribution and evaluation layer. The retailer keeps their existing system of record. This broadcasts the RFP, controls who sees it, collects and ranks bids, and hands the outcome back.

  • Must a vendor author their bid in our tool, or can they submit from anywhere? — Submit from anywhere; structure on ingest. Accept PDF/DOCX from any vendor and extract the response into the common schema so it is rankable. Native authoring is offered as the better path, never required.

  • Day one, a retailer posts an RFP. Where does the bidder pool come from? — The retailer brings their own vendor roster. They import it and invite them. Visibility tiers operate over a retailer-scoped list, not a public market. v1 ships no open discovery.

  • What do bidders actually pay for? — Tools, never access. Seeing RFPs and submitting a bid is free forever. Vendors pay a flat annual subscription for the workspace that helps them win: AI matching, drafting, the reusable compliance vault, status tracking, coordination.

  • Research: Ramp's product, positioning, and business model — Product. Corporate cards, expense management, AP/bill pay, procurement, travel, treasury (>$1B AUM), Ramp Intelligence (a cross-product AI layer, not a SKU), a developer API, and an official MCP server for agent access to spend data.

  • Research: Ramp's online sentiment and the critical case — Sentiment is bimodal, not rosy. The core card + expense product is genuinely well-liked across G2 (~4.8), Capterra (4.9), TrustRadius (~9.1) and — more tellingly — on Hacker News, where commentary is unsolicited. Note Trustpilot sits at 3.5, and unsolicited channels skew more critical than vendor-solicited ones.

  • Define the tenancy, identity, and authorization model — Roster entries (retailer-scoped, unclaimed) vs. claimed global vendor orgs; one org holds issuer and/or vendor capabilities; isolation enforced by Postgres RLS with actor context in transaction-scoped session GUCs.

  • Research: the RFP / sourcing / procurement ecosystem, both sides — It is not novel. It is the incumbent's model.

  • Collect real retail RFPs and vendor responses — Scoring scales are per-document and must never be normalised; price is a rate function, not a scalar; response binding is a reliability gradient from tabbed restatement down to free prose. No completed vendor response could be obtained.

  • Design the visibility and qualification model — Eligibility (durable, per retailer/vendor/category) is separate from audience (per-RFP, ad-hoc or a rule-defined group materialised at issue); audience is fixed at issue while access widens by stage; invited vendors see a teaser until they pass an optional acknowledgement gate.

  • Design the vendor profile and cross-retailer document vault — Vendor attests, we validate only machine-checkable structure, retailer acceptances form a reusable graph shown as an anonymised count with a k-floor (vendor may opt in to name); we curate a small typed catalogue with ad-hoc needs as per-RFP attachments; we compute expiry state, retailers configure its consequence.

  • Specify the entitlement and subscription model — The paid feature is persistence, not access: free vendors bid fully but nothing carries across RFPs, and on lapse the vault stays readable while the reuse machinery stops. Entitlement is resolved once into actor context and asserted per feature, never expressed as row visibility — it gates vendor convenience, never retailer-facing correctness. No retailer sponsorship in v1; the payer column stays.

  • Define the category taxonomy — A curated 50-150 leaf global spine (two-level, UNSPSC-annotated) with retailer-local categories mapped onto it; eligibility and group rules run on the local category and never inherit, while matching and the acceptance graph run on the spine; nodes are immutable with temporal validity and supersession edges, so the historical view is derived rather than versioned.

  • Obtain real completed vendor responses, including a compliance matrix — Closed unresolved: none exist in public form and retrieval was exhausted. v1 reframed as a demoable POC; the schema is designed against a synthesized response corpus, with the resulting under-constraint recorded as an accepted risk.

  • Define the common schema for RFPs and responses — Requirement is the atom with criteria as a weighted overlay mapping to requirement sets; the document stays legally authoritative while the retailer-confirmed extraction drives evaluation, every requirement carrying a provenance span; coverage is three-state with the vendor attesting to their own indeterminates at submit; price is a typed rate function evaluated against a scenario published with the RFP. Scores stay raw and per-document, never normalised.

  • Skeptical review pass over all closed decisions Skeptical review pass over all closed decisions — Two contradictions found and
    ticketed (taxonomy supersession vs. eligibility exactness; the free vendor with no vault), plus
    constraints added to tenancy, the schema, the vault, data release, extraction confirmation, and
    the document catalogue. Nothing previously decided was reversed.

  • Resolve what eligibility references, and whether local categories are mutable — Eligibility references the retailer-local category only, never the spine, so taxonomy churn can never reach an access decision; local categories get the spine's model (immutable identity, editable label, retire not delete); a split propagates grants to every successor and a merge only to the intersection, as explicit event-stamped writes that never widen and never silently revoke; a deprecated spine leaf auto-resolves when unambiguous and raises a remap task when not.

  • Specify the vendor pricing and tier structure — No free tier: a hard $100/mo gate on
    seeing anything, then Pro $350 and Enterprise $1,000, scaling on seats and AI capability and never
    on volume or per-retailer. The rail (vault, cross-retailer reuse, acceptance graph) is in the base
    tier and the AI is the upsell; on lapse live participations run to completion, and eligibility
    never depends on billing. Supersedes #6 and decision 1 of #20.

  • Design the app framework - retailer and vendor surfaces - One app with a combined
    org x capability picker and fully capability-scoped nav; the vendor bids against a requirement-led
    surface that upload imports into, while the retailer's own document stays authoritative with the
    extracted overlay confirmed beside it; the invitation wall shows only issuer, category and
    deadline; the vendor home pairs in-flight work with eligibility health phrased as consequence;
    evaluation is a requirement matrix with ranking left as a view over it. Prototype:
    surface map.

  • Specify the two-party data release rules - Release is a versioned
    disclosure-class x release-level matrix, the level computed by one function over audience,
    stage, participation and acknowledgement; bids stay sealed until the deadline and then open for
    the whole field at once, so bid shopping is structurally impossible; a vendor learns nothing of
    the field and everything about their own response including the retailer's scoring of it; exact
    volumes sit behind the acknowledgement gate, which stays optional but warns hard; export mirrors
    read exactly and is logged. Release never contracts, and win rate exists as no class at all.

  • Design AI bid ranking, scoring, and its defensibility - The model proposes and
    cites, a human commits, and only a commit creates a score of record; routing is by requirement
    kind so gates and all price arithmetic are code the model may locate in but never decide; no
    ordering exists before commits, only deterministic triage, because a provisional rank anchors the
    evaluator invisibly; the criterion-to-requirement mapping is frozen at issue and amending it voids
    affected scores. Suggestions carry a model version, committed scores are never re-derived.

  • Design the extraction confirmation step on both sides - Issue is gated on
    confirming mandatory gates and criterion-mapped requirements individually while informational ones
    bulk-accept, with the ledger ordered by uncertainty rather than document order; the completeness
    sweep blocks only where a second independent pass asserts an obligation nothing covers, and bare
    uncovered text is a report; corrections classify on whether a bidder would answer differently,
    substantive ones extending the deadline and reopening just the affected answer; vendors resolve
    indeterminates and acknowledge gate failures for free, with answer sufficiency as the Pro feature.

  • Assemble the v1 code layout - The destination, reached. Committed as da74362,
    46 files: the domain model as nine schema files with RLS policies beside their tables, the single
    database entry point, the scheduler entry, the entitlement assertion helper, and the three
    enumerated privileged paths. A seam is real types plus a throwing stub naming its ticket, so a
    ticket lands by replacing a body. Drizzle owns what it can diff; functions and the versioned
    matrix are hand-authored. Found on the way: a policy/function ordering cycle resolved with
    plpgsql, at the cost of unvalidated function bodies until first call.

  • Build the synthesized response corpus - Closed demo-sufficient. One archived
    solicitation with hand-authored ground truth, three synthesized responses spanning the binding
    gradient, three distinct rate structures, and two validators asserting the stress-case checklist.
    The lowest bid is disqualified and the highest is strongest on the buyer's own criterion, so a
    ranking that cannot represent absence gets the field backwards. It produced two schema changes -
    nested criteria and a gate no document can satisfy - both applied.

  • Define the v1 component system and visual identity — extends the existing HelmDocs system rather than authoring one. The amber/orange collision resolves as a boundary, not a repaint: the accent is chrome-only and never enters a data surface, and warning never encodes alone — all four semantic tokens promote unchanged. The encoding axis is settled-vs-unsettled, not good-vs-bad: verdicts carry hue, and anything the artifact cannot settle is achromatic and dashed. Density drawn on the evaluation matrix first — gates pinned above the scored body, roll-up parents uncommittable, totals never rounded, a disqualified column struck but visible. Capability is stated in words (Acting as {Org} — {Capability}), never in hue, because it is an authorization boundary. Build list: four components and one promotion PR.

  • Build the clickable POC prototype for the internal demo — the walk is issue → seal → switch → bid → open → evaluate → amend, crossing the capability boundary mid-solicitation because one side alone just looks like a procurement tool. The three behaviour-only decisions are all in it: the sealed field opening at once, the dashed proposal that becomes a score only on a human commit, and the amendment that voids rather than recomputes. Building it found two design bugs a static page hid — roll-ups blending committed with proposed, and voiding not reaching the totals — both now constraints on <EvaluationMatrix>. Throwaway by design; the layout in src/ remains the destination.

  • Define the v1 rate structure types — built, not just decided: src/pricing/ with corpus assertions behind npm run check:pricing. A rate structure is a composition — one base schedule (flat_unit, volume_banded with an explicit whole-basket/marginal flag) plus closed modifiers — evaluated against a closed scenario vocabulary published with the RFP. Three outcomes, not two: priced, shape_unsupported, and input_missing, which is recoverable by asking the vendor. Abstention is null with a reason, never zero, never the vendor's stated figure, and never a partial sum. The derivation is stored as the record with a versioned evaluator; a scenario amendment voids rather than recomputes. Exceptions carry a closed consequence union because one of the three in the corpus has no price at all.

Not yet specified

  • Vendor onboarding, trials, retailer sponsorship, and sales friction. Pinned as a set by
    author direction during the pricing session — weighed and explicitly deferred, not undecided by
    accident. It carries the live risks of the hard gate: a retailer's first sourcing event needs
    every invited supplier to convert before a full field of bids arrives, and suppliers who cannot
    clear $1,200/yr drop out of the retailer's diversity pool. Retailer sponsorship moved here from
    Out of scope
    — it is no longer merely a growth lever but the only proposed answer to that
    second problem.
  • Extraction-side corpus coverage. Friendship PCS has a clean text layer, so the corpus never
    exercises the OCR ladder, and no real tabbed-restatement response was ever obtained. SLC Airport
    (142pp, tabbed A-M, shortlist-for-interviews, percentage-rent pricing of the form
    MAX(1/12 x guarantee, % of receipts)) would cover all four gaps and is the obvious second set.
    Belongs to whoever opens the extraction seam rather than to the demo, and is not sharp enough to
    ticket until that boundary is drawn.
  • Evaluation committees. Real solicitations are scored by a panel - the SLC Airport RFP
    publishes no per-criterion scale at all because a committee judges it - while the scoring model
    resolved here has a single committed_by per criterion. Multiple scorers per criterion, whether
    their scores average or must be reconciled, and who breaks a deadlock, are all unspecified.
    Surfaced by the ranking decision; not sharp enough to ticket until the evaluation surface has
    been used against the synthesized corpus.
  • What "matching" means quantitatively. Vendor<->RFP fit scoring. Cannot be specified before the
    common schema exists, since matching operates over it.
  • Notification and communication design. Who gets told what, through which channel, at which
    lifecycle event. Waits on the lifecycle being pinned down.
  • Productizing the HelmDocs flywheel. Research suggests this may be the actual moat rather than
    a later enhancement, but it cannot be specified until the integration boundary is drawn.
  • Non-retail verticals. The same rail plausibly serves other large buyers. Not sharp enough to
    ticket, and out of the way until retail v1 is specified.

Out of scope

  • Market validation / go-no-go on the business. Whether large retailers will actually adopt a
    third-party venue and whether vendors will actually pay. Ruled out by the destination: this map
    produces a build spec and assumes demand. If the answer is no, the whole map is moot — that is a
    known and accepted risk of this destination.
  • Open marketplace discovery surface. Public RFP feed, vendor self-qualification, browse-and-
    subscribe. Ruled out for v1 by the cold-start decision.
  • System-of-record procurement obligations. SOX controls, records retention, supplier-diversity
    reporting, contract lifecycle management. Ruled out by the distribution-layer decision — these are
    exactly the costs that scale with retailer usage and would eventually break the free promise.
  • HelmDocs flywheel as a v1 deliverable. The author's own framing, and the integration boundary
    ticket covers the interface without building the product.
  • Homepage, pitch, and positioning. Still a different destination than a code layout — it was
    considered as this map's destination and declined. Run it as a separate effort. Its naming
    question is now answered
    and no longer waits on the pitch: this is a HelmDocs product, decided
    in the Notes above.
## Destination A **v1 code layout committed to this repo**: the directory and module structure, the domain model as real schema files, the permission boundaries expressed as code, and the seams where the undecided parts will land. Not a running product — the skeleton a build can start from without being redesigned. Everything on the map serves that. Which means the tickets that determine *structure* — schema, tenancy, visibility, data release, vault, entitlement — gate the destination, while the ones that determine *behaviour* — ranking internals, audit retention, kickoff scope, retailer integrations — can land as modules with stubs and be resolved after the layout exists. **v1 is a demoable proof of concept.** Amended after real completed vendor responses proved unobtainable — the schema is designed against a *synthesized* response corpus written to solicitations we genuinely hold. The RFP half rests on real artifacts; the response half does not. Lightweight but with teeth: the corpus must stress the schema, not flatter it. Nothing built on this schema should be treated as production-ready until at least one real completed response has tested it. See [Obtain real completed vendor responses](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/25). **The destination has been reached.** The v1 code layout is committed - see [Assemble the v1 code layout](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/35). Every remaining ticket is behaviour landing in an existing seam, v1 content filling a vocabulary the surfaces already render, or the demo chain. Nothing left on this map redesigns the skeleton. **One demo artifact is in scope, by author direction.** A **clickable POC prototype** for the first internal meeting - the six surfaces styled and navigable over synthesized corpus data, with no RLS, scheduler, extraction or billing behind them. It sits just past "not a running product" and is admitted deliberately rather than by drift: it is a design artifact built from the same surfaces and corpus the layout uses, not a first build. See [Build the clickable POC prototype for the internal demo](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/37). The code layout remains the destination; the prototype is allowed to be throwaway. Market validation is deliberately **not** part of this map. The map assumes demand and resolves design. See *Out of scope*. ## Notes **Domain.** A two-sided RFP marketplace. Large retailers (Walmart/Target scale) distribute RFPs and evaluate bids for free; revenue comes from a tiered vendor-workspace subscription. The free side is the retailer; the paying side is the bidder. **There is no free vendor tier.** Amended by author direction — a **$100/month floor** gates participation entirely, with Pro at $350/mo and Enterprise at $1,000/mo. This reversed [What do bidders actually pay for?](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/6) and decision 1 of [entitlement](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/20); both carry supersession notices. The cost is recorded rather than resolved: it puts the two sides in tension by construction, and the supplier-diversity exposure is a retailer-side adoption risk. See [Specify the vendor pricing and tier structure](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/34). **This is a HelmDocs product.** Settled by author direction: a sibling to the existing bidder-tools product under one brand, not its own. The design system is therefore *extended* rather than authored - `packages/config/shadcn.css` in `novelpad-desktop` already carries `data-brand="helmdocs"` tokens. **The cost is recorded rather than resolved:** the venue now carries the bidder-tools brand, so a retailer may reasonably ask why the company selling bid-writing AI runs their evaluation. That argument can no longer be made by brand distance and must be made by mechanism - sealed bidding, the human commit, the model bar - which makes those mechanisms demo-critical. See [the component system](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/36). **The central inversion.** The artifact worth standardizing is the **response**, not the RFP. Bid ranking works because responses are machine-comparable, not because RFPs are. So the paying side produces the value the free side receives — the mirror of Ramp, where free software generates the monetized asset. **Skills each session should consult.** `/grill-me` for decision tickets. `/to-issues` once the spec is locked. This repo has no `/research`, `/prototype`, or `/domain-modeling` skill installed — substitute a general-purpose research subagent for research tickets and drive prototypes inline. **Standing preferences.** - The existing bidder-side engine lives in the `novelpad-desktop` monorepo (`packages/ai/src/agents/*`, `packages/core/src/solicitation-extraction/`). Reuse the *thinking* and the prompts; v1 is a separate deployable, so do not reuse the runtime. - **Standing architectural constraint (from the tenancy decision):** isolation is enforced by Postgres row-level security, with actor context carried in transaction-scoped session GUCs. Every subsequent ticket must produce rules that are expressible in policy SQL, and the code layout must funnel all data access through one database entry point. - **Standing guardrail (from the schema decision, reaffirmed by review):** there is no cross-RFP score, no normalised rating, and **no derived vendor win rate**. Scores are raw and per-document. A win rate is a global rating in different clothes and leaks competitive outcomes across the two-party boundary the product is sold on. - Plan, don't do. Tickets resolve decisions; nothing here is a build slice. - Refer to tickets by name, never by bare number. ## Decisions so far <!-- index only: one line per closed ticket, then zoom the link for detail --> - [Where does the transmission system get built?](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/2) — Greenfield, server-authoritative. A new deployable for the retailer side and the transmission network. HelmDocs integrates later across an API/MCP boundary. - [Is this the retailer's system of record, or a layer on their existing stack?](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/3) — Distribution and evaluation layer. The retailer keeps their existing system of record. This broadcasts the RFP, controls who sees it, collects and ranks bids, and hands the outcome back. - [Must a vendor author their bid in our tool, or can they submit from anywhere?](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/4) — Submit from anywhere; structure on ingest. Accept PDF/DOCX from any vendor and extract the response into the common schema so it is rankable. Native authoring is offered as the better path, never required. - [Day one, a retailer posts an RFP. Where does the bidder pool come from?](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/5) — The retailer brings their own vendor roster. They import it and invite them. Visibility tiers operate over a retailer-scoped list, not a public market. v1 ships no open discovery. - [What do bidders actually pay for?](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/6) — Tools, never access. Seeing RFPs and submitting a bid is free forever. Vendors pay a flat annual subscription for the workspace that helps them win: AI matching, drafting, the reusable compliance vault, status tracking, coordination. - [Research: Ramp's product, positioning, and business model](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/7) — Product. Corporate cards, expense management, AP/bill pay, procurement, travel, treasury (>$1B AUM), Ramp Intelligence (a cross-product AI layer, not a SKU), a developer API, and an official MCP server for agent access to spend data. - [Research: Ramp's online sentiment and the critical case](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/8) — Sentiment is bimodal, not rosy. The core card + expense product is genuinely well-liked across G2 (~4.8), Capterra (4.9), TrustRadius (~9.1) and — more tellingly — on Hacker News, where commentary is unsolicited. Note Trustpilot sits at 3.5, and unsolicited channels skew more critical than vendor-solicited ones. - [Define the tenancy, identity, and authorization model](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/11) — Roster entries (retailer-scoped, unclaimed) vs. claimed global vendor orgs; one org holds issuer and/or vendor capabilities; isolation enforced by Postgres RLS with actor context in transaction-scoped session GUCs. - [Research: the RFP / sourcing / procurement ecosystem, both sides](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/9) — It is not novel. It is the incumbent's model. - [Collect real retail RFPs and vendor responses](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/22) — Scoring scales are per-document and must never be normalised; price is a rate function, not a scalar; response binding is a reliability gradient from tabbed restatement down to free prose. No completed vendor response could be obtained. - [Design the visibility and qualification model](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/12) — Eligibility (durable, per retailer/vendor/category) is separate from audience (per-RFP, ad-hoc or a rule-defined group materialised at issue); audience is fixed at issue while access widens by stage; invited vendors see a teaser until they pass an optional acknowledgement gate. - [Design the vendor profile and cross-retailer document vault](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/13) — Vendor attests, we validate only machine-checkable structure, retailer acceptances form a reusable graph shown as an anonymised count with a k-floor (vendor may opt in to name); we curate a small typed catalogue with ad-hoc needs as per-RFP attachments; we compute expiry state, retailers configure its consequence. - [Specify the entitlement and subscription model](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/20) — The paid feature is persistence, not access: free vendors bid fully but nothing carries across RFPs, and on lapse the vault stays readable while the reuse machinery stops. Entitlement is resolved once into actor context and asserted per feature, never expressed as row visibility — it gates vendor convenience, never retailer-facing correctness. No retailer sponsorship in v1; the payer column stays. - [Define the category taxonomy](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/26) — A curated 50-150 leaf global spine (two-level, UNSPSC-annotated) with retailer-local categories mapped onto it; eligibility and group rules run on the local category and never inherit, while matching and the acceptance graph run on the spine; nodes are immutable with temporal validity and supersession edges, so the historical view is derived rather than versioned. - [Obtain real completed vendor responses, including a compliance matrix](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/25) — Closed unresolved: none exist in public form and retrieval was exhausted. v1 reframed as a demoable POC; the schema is designed against a synthesized response corpus, with the resulting under-constraint recorded as an accepted risk. - [Define the common schema for RFPs and responses](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/10) — Requirement is the atom with criteria as a weighted overlay mapping to requirement sets; the document stays legally authoritative while the retailer-confirmed extraction drives evaluation, every requirement carrying a provenance span; coverage is three-state with the vendor attesting to their own indeterminates at submit; price is a typed rate function evaluated against a scenario published with the RFP. Scores stay raw and per-document, never normalised. - **Skeptical review pass over all closed decisions** [Skeptical review pass over all closed decisions](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/33) — Two contradictions found and ticketed (taxonomy supersession vs. eligibility exactness; the free vendor with no vault), plus constraints added to tenancy, the schema, the vault, data release, extraction confirmation, and the document catalogue. Nothing previously decided was reversed. - [Resolve what eligibility references, and whether local categories are mutable](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/31) — Eligibility references the retailer-local category only, never the spine, so taxonomy churn can never reach an access decision; local categories get the spine's model (immutable identity, editable label, retire not delete); a split propagates grants to every successor and a merge only to the intersection, as explicit event-stamped writes that never widen and never silently revoke; a deprecated spine leaf auto-resolves when unambiguous and raises a remap task when not. - [Specify the vendor pricing and tier structure](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/34) — No free tier: a hard $100/mo gate on seeing anything, then Pro $350 and Enterprise $1,000, scaling on seats and AI capability and never on volume or per-retailer. The rail (vault, cross-retailer reuse, acceptance graph) is in the base tier and the AI is the upsell; on lapse live participations run to completion, and eligibility never depends on billing. Supersedes [#6](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/6) and decision 1 of [#20](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/20). - [Design the app framework - retailer and vendor surfaces](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/23) - One app with a combined org x capability picker and fully capability-scoped nav; the vendor bids against a requirement-led surface that upload imports into, while the retailer's own document stays authoritative with the extracted overlay confirmed beside it; the invitation wall shows only issuer, category and deadline; the vendor home pairs in-flight work with eligibility health phrased as consequence; evaluation is a requirement matrix with ranking left as a view over it. Prototype: [surface map](https://claude.ai/code/artifact/91357d1c-96a3-43e0-8a3b-d2da6296b01a). - [Specify the two-party data release rules](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/14) - Release is a versioned disclosure-class x release-level matrix, the level computed by one function over audience, stage, participation and acknowledgement; bids stay sealed until the deadline and then open for the whole field at once, so bid shopping is structurally impossible; a vendor learns nothing of the field and everything about their own response including the retailer's scoring of it; exact volumes sit behind the acknowledgement gate, which stays optional but warns hard; export mirrors read exactly and is logged. Release never contracts, and win rate exists as no class at all. - [Design AI bid ranking, scoring, and its defensibility](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/15) - The model proposes and cites, a human commits, and only a commit creates a score of record; routing is by requirement kind so gates and all price arithmetic are code the model may locate in but never decide; no ordering exists before commits, only deterministic triage, because a provisional rank anchors the evaluator invisibly; the criterion-to-requirement mapping is frozen at issue and amending it voids affected scores. Suggestions carry a model version, committed scores are never re-derived. - [Design the extraction confirmation step on both sides](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/16) - Issue is gated on confirming mandatory gates and criterion-mapped requirements individually while informational ones bulk-accept, with the ledger ordered by uncertainty rather than document order; the completeness sweep blocks only where a second independent pass asserts an obligation nothing covers, and bare uncovered text is a report; corrections classify on whether a bidder would answer differently, substantive ones extending the deadline and reopening just the affected answer; vendors resolve indeterminates and acknowledge gate failures for free, with answer sufficiency as the Pro feature. - [Assemble the v1 code layout](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/35) - **The destination, reached.** Committed as `da74362`, 46 files: the domain model as nine schema files with RLS policies beside their tables, the single database entry point, the scheduler entry, the entitlement assertion helper, and the three enumerated privileged paths. A seam is real types plus a throwing stub naming its ticket, so a ticket lands by replacing a body. Drizzle owns what it can diff; functions and the versioned matrix are hand-authored. Found on the way: a policy/function ordering cycle resolved with plpgsql, at the cost of unvalidated function bodies until first call. - [Build the synthesized response corpus](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/30) - **Closed demo-sufficient.** One archived solicitation with hand-authored ground truth, three synthesized responses spanning the binding gradient, three distinct rate structures, and two validators asserting the stress-case checklist. The lowest bid is disqualified and the highest is strongest on the buyer's own criterion, so a ranking that cannot represent absence gets the field backwards. It produced two schema changes - nested criteria and a gate no document can satisfy - both applied. - [Define the v1 component system and visual identity](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/36) — extends the existing HelmDocs system rather than authoring one. The amber/orange collision resolves as a boundary, not a repaint: **the accent is chrome-only and never enters a data surface**, and **warning never encodes alone** — all four semantic tokens promote unchanged. The encoding axis is settled-vs-unsettled, not good-vs-bad: verdicts carry hue, and anything the artifact cannot settle is achromatic and dashed. Density drawn on the evaluation matrix first — gates pinned above the scored body, roll-up parents uncommittable, totals never rounded, a disqualified column struck but visible. Capability is stated in words (`Acting as {Org} — {Capability}`), never in hue, because it is an authorization boundary. Build list: four components and one promotion PR. - [Build the clickable POC prototype for the internal demo](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/37) — the walk is **issue → seal → switch → bid → open → evaluate → amend**, crossing the capability boundary mid-solicitation because one side alone just looks like a procurement tool. The three behaviour-only decisions are all in it: the sealed field opening at once, the dashed proposal that becomes a score only on a human commit, and the amendment that voids rather than recomputes. Building it found two design bugs a static page hid — roll-ups blending committed with proposed, and voiding not reaching the totals — both now constraints on `<EvaluationMatrix>`. Throwaway by design; the layout in `src/` remains the destination. - [Define the v1 rate structure types](https://gitea.stephenmann.io/christian/helmdocs-proposal-system/issues/29) — built, not just decided: `src/pricing/` with corpus assertions behind `npm run check:pricing`. A rate structure is a **composition** — one base schedule (`flat_unit`, `volume_banded` with an explicit whole-basket/marginal flag) plus closed modifiers — evaluated against a **closed scenario vocabulary** published with the RFP. Three outcomes, not two: priced, `shape_unsupported`, and `input_missing`, which is recoverable by asking the vendor. Abstention is null with a reason, never zero, never the vendor's stated figure, and never a partial sum. The derivation is stored as the record with a versioned evaluator; a scenario amendment voids rather than recomputes. Exceptions carry a closed consequence union because one of the three in the corpus has no price at all. ## Not yet specified - **Vendor onboarding, trials, retailer sponsorship, and sales friction.** Pinned as a set by author direction during the pricing session — weighed and explicitly deferred, not undecided by accident. It carries the live risks of the hard gate: a retailer's first sourcing event needs every invited supplier to convert before a full field of bids arrives, and suppliers who cannot clear $1,200/yr drop out of the retailer's diversity pool. **Retailer sponsorship moved here from Out of scope** — it is no longer merely a growth lever but the only proposed answer to that second problem. - **Extraction-side corpus coverage.** Friendship PCS has a clean text layer, so the corpus never exercises the OCR ladder, and no *real* tabbed-restatement response was ever obtained. SLC Airport (142pp, tabbed A-M, shortlist-for-interviews, percentage-rent pricing of the form `MAX(1/12 x guarantee, % of receipts)`) would cover all four gaps and is the obvious second set. Belongs to whoever opens the extraction seam rather than to the demo, and is not sharp enough to ticket until that boundary is drawn. - **Evaluation committees.** Real solicitations are scored by a panel - the SLC Airport RFP publishes no per-criterion scale at all because a committee judges it - while the scoring model resolved here has a single `committed_by` per criterion. Multiple scorers per criterion, whether their scores average or must be reconciled, and who breaks a deadlock, are all unspecified. Surfaced by the ranking decision; not sharp enough to ticket until the evaluation surface has been used against the synthesized corpus. - **What "matching" means quantitatively.** Vendor<->RFP fit scoring. Cannot be specified before the common schema exists, since matching operates over it. - **Notification and communication design.** Who gets told what, through which channel, at which lifecycle event. Waits on the lifecycle being pinned down. - **Productizing the HelmDocs flywheel.** Research suggests this may be the actual moat rather than a later enhancement, but it cannot be specified until the integration boundary is drawn. - **Non-retail verticals.** The same rail plausibly serves other large buyers. Not sharp enough to ticket, and out of the way until retail v1 is specified. ## Out of scope <!-- ruled beyond the destination; closed, never graduates --> - **Market validation / go-no-go on the business.** Whether large retailers will actually adopt a third-party venue and whether vendors will actually pay. Ruled out by the destination: this map produces a build spec and assumes demand. If the answer is no, the whole map is moot — that is a known and accepted risk of this destination. - **Open marketplace discovery surface.** Public RFP feed, vendor self-qualification, browse-and- subscribe. Ruled out for v1 by the cold-start decision. - **System-of-record procurement obligations.** SOX controls, records retention, supplier-diversity reporting, contract lifecycle management. Ruled out by the distribution-layer decision — these are exactly the costs that scale with retailer usage and would eventually break the free promise. - **HelmDocs flywheel as a v1 deliverable.** The author's own framing, and the integration boundary ticket covers the interface without building the product. - **Homepage, pitch, and positioning.** Still a different destination than a code layout — it was considered as this map's destination and declined. Run it as a separate effort. **Its naming question is now answered** and no longer waits on the pitch: this is a HelmDocs product, decided in the Notes above.
christian added the
wayfinder:map
label 2026-08-02 03:05:50 +00:00
Sign in to join this conversation.
No description provided.