@the-rfp-hub/standard 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/ARTIFACTS.md +85 -0
  2. package/CHANGELOG.md +264 -0
  3. package/LICENSE +121 -0
  4. package/NORMATIVE.md +77 -0
  5. package/PROCESS.md +239 -0
  6. package/README.md +83 -0
  7. package/conformance/README.md +52 -0
  8. package/conformance/v1.0.0/fail/deadline-fixed-date-null.json +22 -0
  9. package/conformance/v1.0.0/fail/deadline-fixed-without-date.json +21 -0
  10. package/conformance/v1.0.0/fail/eligibility-value-not-string.json +21 -0
  11. package/conformance/v1.0.0/fail/empty-sponsoring-organizations.json +11 -0
  12. package/conformance/v1.0.0/fail/missing-matching-type-block.json +14 -0
  13. package/conformance/v1.0.0/fail/missing-required-properties.json +5 -0
  14. package/conformance/v1.0.0/fail/missing-sponsoring-organizations.json +10 -0
  15. package/conformance/v1.0.0/fail/one-block-per-fundingtype.json +18 -0
  16. package/conformance/v1.0.0/fail/source-url-removed.json +17 -0
  17. package/conformance/v1.0.0/fail/status-not-in-enum.json +15 -0
  18. package/conformance/v1.0.0/fail/unknown-top-level-property.json +16 -0
  19. package/conformance/v1.0.0/fail/wrong-fundingtype-value.json +14 -0
  20. package/conformance/v1.0.0/fail/wrong-specversion.json +15 -0
  21. package/conformance/v1.0.0/pass/deadline-rolling-without-date.json +23 -0
  22. package/conformance/v1.0.0/pass/full-featured.json +137 -0
  23. package/conformance/v1.0.0/pass/grant-funding-mechanisms-array.json +27 -0
  24. package/conformance/v1.0.0/pass/grant.json +45 -0
  25. package/conformance/v1.0.0/pass/hackathon.json +67 -0
  26. package/conformance/v1.0.0/pass/minimal-required-only.json +15 -0
  27. package/conformance/v1.0.0/pass/self-identification.json +18 -0
  28. package/conformance/v1.0.0/pass/source-empty-object.json +30 -0
  29. package/dist/index.cjs +902 -0
  30. package/dist/index.cjs.map +1 -0
  31. package/dist/index.d.cts +661 -0
  32. package/dist/index.d.ts +661 -0
  33. package/dist/index.js +896 -0
  34. package/dist/index.js.map +1 -0
  35. package/meta/rfphub-schema.meta.json +131 -0
  36. package/package.json +56 -0
  37. package/registries/deadline-labels.json +38 -0
  38. package/registries/eligibility-keys.json +46 -0
  39. package/registries/entry.schema.json +48 -0
  40. package/registries/index.json +44 -0
  41. package/registries/program-models.json +26 -0
  42. package/schemas/index.json +12 -0
  43. package/schemas/v1.0.0/BENCHMARK.md +160 -0
  44. package/schemas/v1.0.0/CROSSWALK.md +200 -0
  45. package/schemas/v1.0.0/FIELDS.md +530 -0
  46. package/schemas/v1.0.0/STATUS.md +81 -0
  47. package/schemas/v1.0.0/context.jsonld +86 -0
  48. package/schemas/v1.0.0/examples/01-hackathon-fundingmap_1200.json +181 -0
  49. package/schemas/v1.0.0/examples/02-hackathon-fundingmap_1197.json +122 -0
  50. package/schemas/v1.0.0/examples/03-hackathon-fundingmap_1095.json +114 -0
  51. package/schemas/v1.0.0/examples/04-grant-fundingmap_1459.json +67 -0
  52. package/schemas/v1.0.0/examples/05-hackathon-fundingmap_1210.json +97 -0
  53. package/schemas/v1.0.0/examples/06-hackathon-fundingmap_1340.json +91 -0
  54. package/schemas/v1.0.0/examples/07-hackathon-fundingmap_1093.json +89 -0
  55. package/schemas/v1.0.0/examples/08-hackathon-fundingmap_1091.json +89 -0
  56. package/schemas/v1.0.0/examples/09-hackathon-fundingmap_1094.json +89 -0
  57. package/schemas/v1.0.0/examples/10-grant-fundingmap_600.json +65 -0
  58. package/schemas/v1.0.0/examples/11-hackathon-fundingmap_1389.json +83 -0
  59. package/schemas/v1.0.0/examples/12-hackathon-fundingmap_1356.json +83 -0
  60. package/schemas/v1.0.0/examples/13-grant-fundingmap_1458.json +59 -0
  61. package/schemas/v1.0.0/examples/14-grant-fundingmap_1059.json +57 -0
  62. package/schemas/v1.0.0/examples/15-hackathon-fundingmap_1430.json +82 -0
  63. package/schemas/v1.0.0/examples/16-hackathon-fundingmap_1092.json +79 -0
  64. package/schemas/v1.0.0/examples/17-hackathon-fundingmap_1277.json +75 -0
  65. package/schemas/v1.0.0/examples/18-hackathon-fundingmap_1302.json +72 -0
  66. package/schemas/v1.0.0/examples/19-hackathon-fundingmap_1231.json +76 -0
  67. package/schemas/v1.0.0/examples/20-hackathon-fundingmap_1235.json +74 -0
  68. package/schemas/v1.0.0/examples/21-hackathon-fundingmap_1219.json +73 -0
  69. package/schemas/v1.0.0/examples/22-hackathon-fundingmap_1254.json +72 -0
  70. package/schemas/v1.0.0/examples/23-grant-fundingmap_491.json +57 -0
  71. package/schemas/v1.0.0/examples/24-hackathon-fundingmap_1358.json +73 -0
  72. package/schemas/v1.0.0/examples/25-grant-fundingmap_1021.json +57 -0
  73. package/schemas/v1.0.0/examples/26-bounty-fundingmap_1453.json +57 -0
  74. package/schemas/v1.0.0/examples/27-accelerator-fundingmap_1291.json +56 -0
  75. package/schemas/v1.0.0/examples/28-rfp-fundingmap_1242.json +43 -0
  76. package/schemas/v1.0.0/opportunity.schema.json +758 -0
  77. package/spec.config.json +11 -0
@@ -0,0 +1,160 @@
1
+ # RFP Hub Standard v1.0.0 — Real-Data Benchmark
2
+
3
+ Validation of the standard against **real-world funding-opportunity data** from a production
4
+ funding aggregator's public API, plus a ranked benchmark set for schema/CLI testing.
5
+
6
+ **This document is informative** ([`NORMATIVE.md`](../../NORMATIVE.md)). It records a
7
+ measurement, not a rule.
8
+
9
+ > ⚠️ **Two measurements, two shapes.** The 311-entry pull below was run against the schema **as
10
+ > it stood before the 2026-07-27 in-place re-cut**, and has **not** been re-run. The 28 committed
11
+ > example documents **have** been converted to the re-cut shape and re-validated. Read the
12
+ > corpus-wide numbers as evidence about the data model, and the fixture numbers as evidence about
13
+ > the current schema. See the [field mapping table](../../CHANGELOG.md#field-mapping-old--new).
14
+
15
+ ## Result
16
+
17
+ | Metric | Value | Measured against |
18
+ |---|---|---|
19
+ | Unique entries pulled | **311** | pre-re-cut shape |
20
+ | Mapped to source-neutral examples + validated | **289 / 289 valid (0 failures)** | pre-re-cut shape |
21
+ | Curated benchmark fixtures | **28** (in [`examples/`](./examples)) | **re-cut shape — 28/28 valid** |
22
+ | Funding types covered by fixtures | grant, hackathon, bounty, accelerator, rfp | — |
23
+
24
+ 289 of the 311 pulled entries mapped to public-source, source-neutral examples and all validated
25
+ with 0 failures — evidence that the data model is faithful to a real funding corpus. The
26
+ remaining ~22 were set aside for lacking a public original-posting URL or to keep the sample free
27
+ of any one aggregator's branding. Example ids use a neutral `fundingmap:` namespace.
28
+
29
+ The **28 committed fixtures are the live claim**: they were converted field-by-field to the
30
+ re-cut shape and all 28 validate against the current
31
+ [`opportunity.schema.json`](./opportunity.schema.json).
32
+
33
+ ```bash
34
+ npx rfphub-validate packages/standard/schemas/v1.0.0/examples
35
+ # 28 passed, 0 failed
36
+ ```
37
+
38
+ ## What the re-cut conversion did to these 28 documents
39
+
40
+ Mechanical, and lossless where a real value existed. Each move follows a row in the
41
+ [field mapping table](../../CHANGELOG.md#field-mapping-old--new):
42
+
43
+ - **`type` → `fundingType`**, and each document's type block re-keyed to match. No document
44
+ carried a second, non-matching type block, so the newly enforced one-block-per-type rule cost
45
+ nothing here.
46
+ - **`organization` → `sponsoringOrganizations[0]`** — a wrap, no data change. No fixture needed
47
+ `operatingOrganizations`.
48
+ - **`source.url` has no successor.** Where a document had no `applicationUrl`, the old source URL
49
+ became the `applicationUrl` — it was the only link-back target left. Where `applicationUrl`
50
+ already pointed somewhere else, the source URL was preserved in **`resourceLinks`** rather than
51
+ dropped: **6 of the 28 documents** carry one for that reason.
52
+ - **Hackathon date folding.** `registrationDeadline`, `submissionDeadline`, `startDate` and
53
+ `endDate` all folded into `deadlines[]` with labels `registration` / `submission` /
54
+ `event start` / `event end`; `closesAt` and `rfp.proposalDeadline` folded in as `application`.
55
+ Across the corpus this produced **28 `application`, 18 `registration`, 19 `event start` and 19
56
+ `event end`** entries — which is exactly why a consumer must select by label: on 19 of these
57
+ documents `deadlines[0]` is an event boundary, not a deadline.
58
+ - **`funding.totalBudget` → `budget`**, `amountDistributed` → `allocated`. Only one document had
59
+ a non-zero `funding.awardsToDate`, a field with no successor; that value was preserved under
60
+ **`extensions`** rather than deleted. It is the only fixture using `extensions`.
61
+ - No fixture exercises `milestones[]`, `eligibility`, `serviceAgreement` or `prerequisites` —
62
+ the source corpus carries none of them. Those fields are exercised by the
63
+ [conformance suite](../../conformance/v1.0.0), not by this benchmark.
64
+
65
+ ## Methodology (original pull)
66
+
67
+ - **Source:** a production funding aggregator's public REST API (`isValid=accepted`, sorted by
68
+ recency); 3 general pages (100/page) plus one page per type for diversity, deduped to 311.
69
+ - **Mapping:** each entry mapped to the Standard's public shape; source-system internal fields
70
+ are dropped (the standard is source-agnostic).
71
+ - **Validation:** ajv 8 (`ajv/dist/2020`) + `ajv-formats`, `strict: true, strictRequired: false`.
72
+ - **Fill score** — count of *populated* Standard fields (scalar leaves + non-empty arrays and
73
+ their items), excluding the always-present `specVersion`/`id`/type discriminator and
74
+ `extensions`. Higher = richer entry, better for exercising schema breadth.
75
+ - **Activity score** — `status` weight (`open` 4 / `upcoming` 3 / `closed` 1 / `archived` 0)
76
+ `+3` if the application deadline is in the future, `+1` if `opensAt` is in the future,
77
+ `+` recency (up to `+4`, linearly decaying over 1 year from `updatedAt`). *(Computed on the
78
+ pre-re-cut single `closesAt` scalar; under the re-cut shape the same score would read the
79
+ `application`-labelled entry of `deadlines[]`.)*
80
+
81
+ Both scores are **ranking heuristics for choosing fixtures**, not quality metrics of the
82
+ standard, and neither is normative.
83
+
84
+ ## Per-type coverage (original pull)
85
+
86
+ | Type | Sampled | Valid |
87
+ |---|--:|--:|
88
+ | grant | 99 | 99 |
89
+ | hackathon | 130 | 130 |
90
+ | bounty | 42 | 42 |
91
+ | accelerator | 16 | 16 |
92
+ | rfp | 2 | 2 |
93
+ | **vc_fund** | **0** | — |
94
+
95
+ > ⚠️ **`vc_fund` coverage gap:** there are **zero** VC-fund entries in the source data, so the
96
+ > `vc_fund` block still cannot be benchmarked against real data. It is covered by the conformance
97
+ > suite only; real VC-fund entries should be added during later seeding. `rfp` is also thin
98
+ > (2 entries) — worth expanding given this is the *RFP* Hub.
99
+
100
+ ## Benchmark fixture set
101
+
102
+ The 28 fixtures in [`examples/`](./examples) are the top entries by fill, with type diversity
103
+ injected (≥1 of each available type): **19 hackathon, 6 grant, 1 bounty, 1 accelerator, 1 rfp**.
104
+ They serve as (a) the real-data validation corpus, (b) golden inputs for the `rfphub-validate`
105
+ CLI, and (c) realistic seed candidates for the public dataset. They are **examples, not
106
+ conformance cases** — the pass/fail rule documents live in
107
+ [`conformance/v1.0.0/`](../../conformance/v1.0.0). The single best all-round benchmark entry is
108
+ **Prezenti Boost Pool S2** (`fundingmap:1459`) — open, future deadline, and high fill.
109
+
110
+ ### Top 15 by FILL (most complete entries, original pull)
111
+
112
+ | # | Fill | Activity | Type | Status | Name | id |
113
+ |--:|--:|--:|---|---|---|---|
114
+ | 1 | 73 | 2.86 | hackathon | archived | Electrothon 8.0 | fundingmap:1200 |
115
+ | 2 | 49 | 2.86 | hackathon | archived | HACKANOVA 5.O | fundingmap:1197 |
116
+ | 3 | 46 | 3.11 | hackathon | archived | ETHGlobal Cannes 2026 | fundingmap:1095 |
117
+ | 4 | 42 | 10.58 | grant | open | Prezenti Boost Pool S2 | fundingmap:1459 |
118
+ | 5 | 39 | 2.92 | hackathon | archived | HackByte 4.0 | fundingmap:1210 |
119
+ | 6 | 37 | 3.13 | hackathon | archived | Hack-Helix | fundingmap:1340 |
120
+ | 7 | 36 | 9.81 | hackathon | upcoming | ETHGlobal Lisbon 2026 | fundingmap:1093 |
121
+ | 8 | 36 | 9.81 | hackathon | upcoming | ETHGlobal Mumbai | fundingmap:1091 |
122
+ | 9 | 36 | 3.88 | hackathon | archived | ETHGlobal New York 2026 | fundingmap:1094 |
123
+ | 10 | 35 | 4.58 | grant | closed | Prezenti Mint Round | fundingmap:600 |
124
+ | 11 | 34 | 3.44 | hackathon | archived | Locus' Paygentic Hackathon - #2 | fundingmap:1389 |
125
+ | 12 | 34 | 3.22 | hackathon | archived | Locus' Paygentic Hackathon - #1 | fundingmap:1356 |
126
+ | 13 | 33 | 10.58 | grant | open | Prezenti Anchor Pool | fundingmap:1458 |
127
+ | 14 | 33 | 3.87 | grant | closed | Build Agents for the Real World Hackathon V2 | fundingmap:1059 |
128
+ | 15 | 33 | 3.44 | hackathon | archived | Locus' Paygentic Hackathon - #4 | fundingmap:1430 |
129
+
130
+ ### Top 15 by ACTIVITY (most live opportunities, original pull)
131
+
132
+ | # | Activity | Fill | Type | Status | Name | id |
133
+ |--:|--:|--:|---|---|---|---|
134
+ | 1 | 10.91 | 27 | hackathon | upcoming | FutureForge Hackathon 2026 | fundingmap:1494 |
135
+ | 2 | 10.91 | 25 | hackathon | upcoming | MicroCraft - Vibeathon | fundingmap:1493 |
136
+ | 3 | 10.91 | 25 | hackathon | upcoming | Ignisys 1.O | fundingmap:1495 |
137
+ | 4 | 10.81 | 29 | hackathon | upcoming | DSU DEVHACK 3.0 | fundingmap:1488 |
138
+ | 5 | 10.81 | 25 | hackathon | upcoming | Hack On Hills 8.0 | fundingmap:1490 |
139
+ | 6 | 10.81 | 25 | hackathon | upcoming | Hack4Brahma 2.0 | fundingmap:1489 |
140
+ | 7 | 10.81 | 25 | hackathon | upcoming | HackNex Season 2 | fundingmap:1483 |
141
+ | 8 | 10.81 | 25 | hackathon | upcoming | SheBuilds Chennai Hack | fundingmap:1487 |
142
+ | 9 | 10.81 | 25 | hackathon | upcoming | ccuhacks | fundingmap:1478 |
143
+ | 10 | 10.81 | 25 | hackathon | upcoming | HACKER HOUSE GOA 2026 | fundingmap:1480 |
144
+ | 11 | 10.58 | 42 | grant | open | Prezenti Boost Pool S2 | fundingmap:1459 |
145
+ | 12 | 10.58 | 33 | grant | open | Prezenti Anchor Pool | fundingmap:1458 |
146
+ | 13 | 10.24 | 25 | hackathon | upcoming | Citadel Hackathon - Season 1 | fundingmap:1390 |
147
+ | 14 | 10.05 | 24 | grant | open | infraBUIDL(AI) | fundingmap:938 |
148
+ | 15 | 10.05 | 15 | grant | open | Arbitrum Audit Program | fundingmap:1320 |
149
+
150
+ *Both scores are as measured on the pre-re-cut shape at pull time. The re-cut removed some fields
151
+ and added others, so the absolute fill numbers would shift, and activity scores decay with the
152
+ calendar; the ranking that selected these fixtures would not change materially.*
153
+
154
+ ## Reproduce
155
+
156
+ An internal pull/map/rank script reads a production funding aggregator's public API, maps each
157
+ entry to the Standard, validates with ajv, and ranks by fill/activity. Raw pulled data and full
158
+ scored rankings stay local (reproducible from the public API) and are not committed. Re-running
159
+ it against the re-cut shape is worthwhile before the next cut, and would replace the pre-re-cut
160
+ figures above.
@@ -0,0 +1,200 @@
1
+ # RFP Hub Standard ↔ DAOIP-5 ↔ schema.org/Grant
2
+
3
+ The project's brief is to **build on** the **DAOIP-5 Grants Metadata Standard** and
4
+ **schema.org/Grant** rather than start from scratch. This crosswalk documents how the RFP Hub
5
+ Standard v1.0.0 maps onto both, so a consumer can translate between them.
6
+
7
+ **This document is informative** — the schema is normative
8
+ ([`NORMATIVE.md`](../../NORMATIVE.md)). It is also corrigible: a wrong mapping row can be fixed
9
+ outside the release cycle.
10
+
11
+ - **schema.org/Grant** is intentionally minimal (a handful of properties on `Thing` + `funder`,
12
+ `sponsor`, `amount`, `fundedItem`). Every one of its fields has a clean RFP Hub equivalent.
13
+ - **DAOIP-5** is a JSON-LD family of objects: **Grant System** (the administering body),
14
+ **Grant Pool** (an open funding opportunity), **Project**, **Application**. The RFP Hub
15
+ **Opportunity** is closest to a **Grant Pool**; our **Organization** ≈ a **Grant System**.
16
+ DAOIP-5 is grant-centric, so our non-grant types (hackathon/bounty/accelerator/vc_fund) and
17
+ several fields extend beyond it.
18
+
19
+ > ⚠️ **v1.0.0 was re-cut in place on 2026-07-27** and this crosswalk was reissued with it. If you
20
+ > are holding a copy of this file that maps `organization`, `source.url`, `closesAt`,
21
+ > `funding.totalBudget` or `grant.fundingMechanism`, it predates the re-cut — see
22
+ > the [field mapping table](../../CHANGELOG.md#field-mapping-old--new) in `CHANGELOG.md`.
23
+
24
+ ## Field mapping (Opportunity)
25
+
26
+ "—" means **no equivalent exists** in that standard. It is not shorthand for "not yet mapped".
27
+
28
+ ### Identity and description
29
+
30
+ | RFP Hub v1.0.0 | schema.org/Grant | DAOIP-5 (Grant Pool unless noted) |
31
+ |---|---|---|
32
+ | `id` | `identifier` | `id` |
33
+ | `title` | `name` | `name` |
34
+ | `description` | `description` | `description` |
35
+ | `summary` | `disambiguatingDescription` | — |
36
+ | `fundingType` (6 values) | — (`Grant` is the only type) | — (a Grant Pool is a grant by definition) |
37
+ | `status` (4 values) | — | `isOpen` (boolean) — **lossy both ways**: four lifecycle values collapse to one boolean, and `upcoming` vs `open` is unrecoverable |
38
+ | `specVersion` | `schemaVersion` | — |
39
+
40
+ ### Organisations
41
+
42
+ | RFP Hub v1.0.0 | schema.org/Grant | DAOIP-5 |
43
+ |---|---|---|
44
+ | `sponsoringOrganizations[]` | `funder` (Organization) — **repeatable, so the array maps cleanly** | **Grant System** (the administering body) |
45
+ | `sponsoringOrganizations[0].name` | `funder.name` | grant system `name` |
46
+ | `operatingOrganizations[]` | `sponsor` — **loose**: schema.org's `sponsor` is another funding-side role, not an operator. The JSON-LD context uses it as the nearest available term; a consumer that needs "who runs intake" must read the RFP Hub field | — |
47
+ | `organization.contacts[]` | `contactPoint` | — |
48
+ | `organization.logoUrl` / `bannerUrl` | `logo` / `image` | — |
49
+
50
+ ### Money
51
+
52
+ | RFP Hub v1.0.0 | schema.org/Grant | DAOIP-5 |
53
+ |---|---|---|
54
+ | `funding.budget` | `amount` (MonetaryAmount) | `totalGrantPoolSize[].amount` |
55
+ | `funding.currency` | `amount.currency` | `totalGrantPoolSize[].denomination` |
56
+ | `funding.allocated` (committed to date) | — | — |
57
+ | `funding.minAward` / `maxAward` | — | — |
58
+ | `milestones[]` | — | — (no Grant Pool equivalent) |
59
+ | `bounty.reward`, `hackathon.prizes[]`, `accelerator.funding` | `amount` (loosely) | — |
60
+
61
+ **Cardinality divergence.** DAOIP-5's `totalGrantPoolSize` is an **array** of
62
+ `{amount, denomination}`; the RFP Hub envelope is **single-currency by design**. Exporting to
63
+ DAOIP-5 emits a one-element array. Importing from DAOIP-5 takes the primary amount and must put
64
+ any further denominations in `description` or `extensions` — that direction is lossy, and
65
+ deliberately so.
66
+
67
+ ### Dates
68
+
69
+ | RFP Hub v1.0.0 | schema.org/Grant | DAOIP-5 |
70
+ |---|---|---|
71
+ | `deadlines[]` where `label = "application"` | — | `closeDate` |
72
+ | `deadlines[]` — every other label (`registration`, `submission`, `event start`, `event end`, `community feedback`) | — | — |
73
+ | `deadlines[].type = "rolling"` | — | — (DAOIP-5 has no rolling form; `isOpen` carries what it can) |
74
+ | `opensAt` | `startDate` | — |
75
+ | `postedAt` | `datePublished` | — |
76
+ | `createdAt` / `updatedAt` | `dateCreated` / `dateModified` | — |
77
+
78
+ **Cardinality divergence.** DAOIP-5 has one scalar `closeDate`; the RFP Hub has an array of
79
+ labelled deadlines. Exporting takes the earliest future `application` deadline. Importing yields
80
+ a single `{type: "fixed", date, label: "application"}` entry — every other deadline the source
81
+ had, if it had any, was already lost before it reached us.
82
+
83
+ ### Eligibility, requirements, links
84
+
85
+ | RFP Hub v1.0.0 | schema.org/Grant | DAOIP-5 |
86
+ |---|---|---|
87
+ | `applicationUrl` | `url` | `applicationsURI` |
88
+ | `website` | `sameAs` | — (`governanceURI` is a different thing) |
89
+ | `socialLinks` | `sameAs` | — |
90
+ | `resourceLinks` | `citation` (loose) | — |
91
+ | `eligibility` (open key→value map) | `eligibleCustomerType` (loose) | — |
92
+ | `prerequisites` | `competencyRequired` (loose) | — |
93
+ | `serviceAgreement` | — | — |
94
+ | `rfp.scope` / `rfp.requirements` | — | — |
95
+ | `categories` / `tags` | `about` / `keywords` (loose) | — |
96
+ | `ecosystems` / `networks` | — | — (RFP Hub extension) |
97
+
98
+ ### Grant mechanics and provenance
99
+
100
+ | RFP Hub v1.0.0 | schema.org/Grant | DAOIP-5 |
101
+ |---|---|---|
102
+ | `grant.fundingMechanisms[]` | — | `grantFundingMechanism` — **singular there, array here** |
103
+ | `grant.programModel` | — | — |
104
+ | `grant.milestoneBased` / `grant.recurring` | — | — |
105
+ | `source.publisher` | `publisher` | — |
106
+ | `source.submittedBy` | `contributor` | — |
107
+ | `source.submittedAt` | `dateCreated` | — |
108
+ | `source.snapshotUrl` | `archivedAt` | — |
109
+ | `source.ingestedVia` / `originalId` / `verifiedAgainstSource` / `verifiedAt` | — | — (RFP Hub provenance extension) |
110
+ | `extensions` | — | `extensions` |
111
+
112
+ **Cardinality divergence.** `grant.fundingMechanisms` is an array (mechanisms co-occur — a fixed
113
+ grant plus a matching grant in the same program); DAOIP-5's `grantFundingMechanism` is a scalar.
114
+ Export takes the first element or joins them; either choice loses information, so the export
115
+ adapter should pick one and document it. Value-level alignment is unchanged: `retroactive`,
116
+ `proactive`, `streaming`, `quadratic`, `matching`, `other` map onto DAOIP-5's vocabulary
117
+ ("Retroactive", "Direct Grants", "Quadratic Funding", …).
118
+
119
+ ### Type blocks beyond both standards
120
+
121
+ `hackathon`, `bounty`, `accelerator` and `vc_fund` have **no equivalent** in either standard.
122
+ DAOIP-5 models grants; schema.org models `Grant`. Everything inside those four blocks —
123
+ tracks, prizes, team sizes, check sizes, investment stages, equity, batch size — is an RFP Hub
124
+ extension and does not round-trip.
125
+
126
+ Self-identification keys (`$schema`, `@context`, `@type`) are JSON Schema and JSON-LD machinery,
127
+ not domain fields; they have no crosswalk row.
128
+
129
+ ## Alignment status
130
+
131
+ - ✅ **Crosswalk verified** against the published DAOIP-5 spec (Grant System + Grant Pool
132
+ objects) and schema.org/Grant. **Every schema.org/Grant property and every DAOIP-5 Grant Pool
133
+ field still has an RFP Hub equivalent** — alignment survived the re-cut in that direction.
134
+ - ⚠️ **The earlier claim that "no v1.0.0 field had to change to align" no longer holds, and
135
+ should not be repeated.** Fields *did* change — not to chase alignment, but because the
136
+ 2026-07-27 design decisions re-cut the shape. Three mappings were reissued as a direct
137
+ consequence:
138
+ - `source.url` → the `sameAs` sense **has no successor**. `applicationUrl` carries the
139
+ `schema:url` / `applicationsURI` sense alone; a publisher who needs the original posting
140
+ on the record puts it in `resourceLinks`, which maps only loosely to `schema:citation`.
141
+ - `organization` → `sponsoringOrganizations[]`, which maps *better* than before: schema.org
142
+ carries `funder` **and** `sponsor`, and both are repeatable.
143
+ - `closesAt` → `deadlines[]`, which maps *worse* than before: one scalar became a labelled
144
+ array and only the `application` label round-trips to `closeDate`.
145
+
146
+ See the [field mapping table](../../CHANGELOG.md#field-mapping-old--new) for the full
147
+ field-by-field record and
148
+ [`adr/0002`](../../../../adr/0002-v-next-field-recut.md) for why.
149
+ - ✅ **JSON-LD `@context` shipped** — [`context.jsonld`](./context.jsonld), covering every
150
+ top-level property of the re-cut shape (CI fails on context↔schema drift in either direction).
151
+ Term IRIs are **versionless** (`https://github.com/The-RFP-Hub/the-rfp-hub/ns/draft/rfp#`, provisional
152
+ pending a canonical domain); the context *document* is what
153
+ gets versioned. Every field with no schema.org or DAOIP-5 equivalent resolves under the RFP Hub
154
+ vocabulary, so nothing is dropped when a document is read as linked data.
155
+ - ⬜ **DAOIP-5 `grantPools` export** (optional, planned) — a one-way *output adapter* that emits
156
+ grant-type opportunities as DAOIP-5 `grantPools` JSON, applying the three cardinality
157
+ reductions above. This is an export *format*, **not** a prerequisite for the standard being
158
+ aligned. See [`ARTIFACTS.md`](../../ARTIFACTS.md).
159
+
160
+ ## Using the JSON-LD context
161
+
162
+ A document may carry `@context` and `@type` at the top level and **still validate** — the
163
+ three self-identification keys are permitted against `additionalProperties: false` for exactly
164
+ this reason ([`adr/0003`](../../../../adr/0003-instance-self-identification-and-version-pattern.md)).
165
+ The example below is a conforming RFP Hub opportunity:
166
+
167
+ ```json
168
+ {
169
+ "$schema": "https://raw.githubusercontent.com/The-RFP-Hub/the-rfp-hub/main/packages/standard/schemas/v1.0.0/opportunity.schema.json",
170
+ "@context": "https://raw.githubusercontent.com/The-RFP-Hub/the-rfp-hub/main/packages/standard/schemas/v1.0.0/context.jsonld",
171
+ "@type": "schema:Grant",
172
+ "specVersion": "1.0.0",
173
+ "id": "example:grant-1",
174
+ "fundingType": "grant",
175
+ "title": "Example Grants",
176
+ "description": "An example grant program, published as both plain JSON and linked data.",
177
+ "status": "open",
178
+ "sponsoringOrganizations": [{ "name": "Example Foundation" }],
179
+ "source": { "publisher": "example", "ingestedVia": "publisher_api" },
180
+ "applicationUrl": "https://example.org/grants/apply",
181
+ "deadlines": [
182
+ { "type": "fixed", "date": "2026-12-31T23:59:59.000Z", "label": "application" }
183
+ ],
184
+ "funding": { "currency": "USD", "budget": 250000 },
185
+ "grant": { "fundingMechanisms": ["retroactive", "matching"] }
186
+ }
187
+ ```
188
+
189
+ A JSON-LD processor expands this to a `schema:Grant` with `schema:identifier` / `schema:name` /
190
+ `schema:description` / `schema:funder` / `schema:url`, with `budget` under
191
+ `daoip5:totalGrantPoolSize` and `fundingMechanisms` under `daoip5:grantFundingMechanism`.
192
+
193
+ Verify it yourself:
194
+
195
+ ```bash
196
+ npx rfphub-validate that-document.json
197
+ ```
198
+
199
+ *(The `$id` and `@context` hosts are placeholders pending the project domain decision — the
200
+ documents they name are in this directory.)*