@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.
- package/ARTIFACTS.md +85 -0
- package/CHANGELOG.md +264 -0
- package/LICENSE +121 -0
- package/NORMATIVE.md +77 -0
- package/PROCESS.md +239 -0
- package/README.md +83 -0
- package/conformance/README.md +52 -0
- package/conformance/v1.0.0/fail/deadline-fixed-date-null.json +22 -0
- package/conformance/v1.0.0/fail/deadline-fixed-without-date.json +21 -0
- package/conformance/v1.0.0/fail/eligibility-value-not-string.json +21 -0
- package/conformance/v1.0.0/fail/empty-sponsoring-organizations.json +11 -0
- package/conformance/v1.0.0/fail/missing-matching-type-block.json +14 -0
- package/conformance/v1.0.0/fail/missing-required-properties.json +5 -0
- package/conformance/v1.0.0/fail/missing-sponsoring-organizations.json +10 -0
- package/conformance/v1.0.0/fail/one-block-per-fundingtype.json +18 -0
- package/conformance/v1.0.0/fail/source-url-removed.json +17 -0
- package/conformance/v1.0.0/fail/status-not-in-enum.json +15 -0
- package/conformance/v1.0.0/fail/unknown-top-level-property.json +16 -0
- package/conformance/v1.0.0/fail/wrong-fundingtype-value.json +14 -0
- package/conformance/v1.0.0/fail/wrong-specversion.json +15 -0
- package/conformance/v1.0.0/pass/deadline-rolling-without-date.json +23 -0
- package/conformance/v1.0.0/pass/full-featured.json +137 -0
- package/conformance/v1.0.0/pass/grant-funding-mechanisms-array.json +27 -0
- package/conformance/v1.0.0/pass/grant.json +45 -0
- package/conformance/v1.0.0/pass/hackathon.json +67 -0
- package/conformance/v1.0.0/pass/minimal-required-only.json +15 -0
- package/conformance/v1.0.0/pass/self-identification.json +18 -0
- package/conformance/v1.0.0/pass/source-empty-object.json +30 -0
- package/dist/index.cjs +902 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +661 -0
- package/dist/index.d.ts +661 -0
- package/dist/index.js +896 -0
- package/dist/index.js.map +1 -0
- package/meta/rfphub-schema.meta.json +131 -0
- package/package.json +56 -0
- package/registries/deadline-labels.json +38 -0
- package/registries/eligibility-keys.json +46 -0
- package/registries/entry.schema.json +48 -0
- package/registries/index.json +44 -0
- package/registries/program-models.json +26 -0
- package/schemas/index.json +12 -0
- package/schemas/v1.0.0/BENCHMARK.md +160 -0
- package/schemas/v1.0.0/CROSSWALK.md +200 -0
- package/schemas/v1.0.0/FIELDS.md +530 -0
- package/schemas/v1.0.0/STATUS.md +81 -0
- package/schemas/v1.0.0/context.jsonld +86 -0
- package/schemas/v1.0.0/examples/01-hackathon-fundingmap_1200.json +181 -0
- package/schemas/v1.0.0/examples/02-hackathon-fundingmap_1197.json +122 -0
- package/schemas/v1.0.0/examples/03-hackathon-fundingmap_1095.json +114 -0
- package/schemas/v1.0.0/examples/04-grant-fundingmap_1459.json +67 -0
- package/schemas/v1.0.0/examples/05-hackathon-fundingmap_1210.json +97 -0
- package/schemas/v1.0.0/examples/06-hackathon-fundingmap_1340.json +91 -0
- package/schemas/v1.0.0/examples/07-hackathon-fundingmap_1093.json +89 -0
- package/schemas/v1.0.0/examples/08-hackathon-fundingmap_1091.json +89 -0
- package/schemas/v1.0.0/examples/09-hackathon-fundingmap_1094.json +89 -0
- package/schemas/v1.0.0/examples/10-grant-fundingmap_600.json +65 -0
- package/schemas/v1.0.0/examples/11-hackathon-fundingmap_1389.json +83 -0
- package/schemas/v1.0.0/examples/12-hackathon-fundingmap_1356.json +83 -0
- package/schemas/v1.0.0/examples/13-grant-fundingmap_1458.json +59 -0
- package/schemas/v1.0.0/examples/14-grant-fundingmap_1059.json +57 -0
- package/schemas/v1.0.0/examples/15-hackathon-fundingmap_1430.json +82 -0
- package/schemas/v1.0.0/examples/16-hackathon-fundingmap_1092.json +79 -0
- package/schemas/v1.0.0/examples/17-hackathon-fundingmap_1277.json +75 -0
- package/schemas/v1.0.0/examples/18-hackathon-fundingmap_1302.json +72 -0
- package/schemas/v1.0.0/examples/19-hackathon-fundingmap_1231.json +76 -0
- package/schemas/v1.0.0/examples/20-hackathon-fundingmap_1235.json +74 -0
- package/schemas/v1.0.0/examples/21-hackathon-fundingmap_1219.json +73 -0
- package/schemas/v1.0.0/examples/22-hackathon-fundingmap_1254.json +72 -0
- package/schemas/v1.0.0/examples/23-grant-fundingmap_491.json +57 -0
- package/schemas/v1.0.0/examples/24-hackathon-fundingmap_1358.json +73 -0
- package/schemas/v1.0.0/examples/25-grant-fundingmap_1021.json +57 -0
- package/schemas/v1.0.0/examples/26-bounty-fundingmap_1453.json +57 -0
- package/schemas/v1.0.0/examples/27-accelerator-fundingmap_1291.json +56 -0
- package/schemas/v1.0.0/examples/28-rfp-fundingmap_1242.json +43 -0
- package/schemas/v1.0.0/opportunity.schema.json +758 -0
- 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.)*
|