-
-
Notice 713597-2026: the demo firm can't meet the EUR 1,400,000 turnover floor alone. The clause that sets it is quoted from TED.
-
Lot 1 reads Not met alone. Code compared the turnover floor with the firm's figures, and Article 63 lets a partner's capacity count.
-
The German clause under the answer, the sentence that sets the floor underlined. Code found the model's quote in it word for word.
-
Notice 699142-2026, criterion 6: code found none of the model's three quotes in the clause, so it is marked Not read, not guessed.
-
The recorded run: Nemotron 3 Super on Nebius Token Factory, USD 0.275838 for 288 lots, 1,789 quotes verified and 76 refused.
-
One run on 22 Oct 2026 over 323 open IT notices: the demo firm gets 5 Not met alone and 318 Ask first. None is a clean Go.
-
Tavily search on the buyer of notice 699958-2026: four tender pages, shown apart as unchecked results that never change the answer.
-
Notice 713612-2026 publishes no selection criteria, and this version doesn't read the documents yet, so its answer is Ask first.
You run a 19-person IT firm in the Netherlands. A German federal buyer has just put a framework contract on TED, the EU's public tender journal, that your team could deliver. Can you even take part? For that notice, 713597-2026, Pagefifty's answer is "Not met alone": the buyer wants EUR 1,400,000 a year in turnover in this field, your firm averaged EUR 1,180,000 over the last three years, and even its best year, EUR 1,240,000, falls short. The German sentence that sets the floor is quoted under the answer.
On 22 October Pagefifty checked 323 open IT notices from Dutch, Belgian and German buyers. NVIDIA's open model Nemotron 3 Super, on Nebius Token Factory, read the 288 lots in the 200 notices that publish their selection criteria, for USD 0.28 at Token Factory's list price. Code refused 76 of the model's 1,865 quotes because it could not verify them in the tender's text.
Try it, nothing to install: pagefifty.atfyigtaran.workers.dev. The home page opens on the near miss above, checked against an invented demo firm.
The recorded run, no key needed: examples/2026-10-22, with the replay steps.
The code (MIT): github.com/voyagi/pagefifty
Every page comes in Light, Dark and Device themes, and an automated axe audit on 24 October found 0 violations on 36 audited pages. Judging falls after most of these deadlines: every example page shows the tender as it stood at the 22 October capture.
Track: Best Apps and Agents
How to spend three minutes here
- On the home page (no signup, no upload), press "Open the example verdict" and read "Not met alone" at the top of Lot 1. On a wide screen, scroll the right-hand pane to the clause, where the sentence that sets the floor is underlined.
- Press "Open notice on TED" and check that quote against the buyer's own notice.
- Open notice 699142-2026, expand "Other requirements in this lot" and find criterion 6, "Not read": three quotes the code refused.
With more time: the home page counts the whole run under "What one run found", "Tenders" checks the same notices against a profile of your own, kept in your browser, and How the AI is used, in every page's footer, gives the model, its region, the tokens and the cost.
Page fifty
On paper, EU public tenders are open to small firms. What keeps a small firm out is usually one line: a minimum yearly turnover, a staff count per role, a certificate. That line sits in the selection criteria, in German, Dutch or French, and when the notice sends you to the procurement documents it can be fifty pages into the pack. Someone at the firm has to read all of it to find that one line before anyone decides to bid. In the ESPD, the EU's standard self-declaration form, a firm declares that it meets these criteria and backs that up with documents when the buyer asks, at the latest before award. A firm that cannot back its declaration loses the contract, and a serious or negligent misstatement is itself a ground for exclusion (Directive 2014/24/EU, Article 57(4)(h) and (i)).
In September I counted. Of the 363 IT notices Dutch, Belgian and German buyers published on TED in the first half of that month, 350 were still open by their deadlines. 57 of those stated a turnover floor, and 31 of them were out of reach for a firm turning over EUR 1 million a year on its own. The directive also lets a firm rely on another firm's turnover, staff and references (Directive 2014/24/EU, Article 63), on conditions: the partner commits its resources and is checked like you, its references count only if it does that part of the work, and for turnover the buyer may make it jointly liable for the contract. So when a small firm falls short on any of them, the useful answer is often not a flat no. It's "not on your own", with the clause that says so.
In the 22 October run, 123 of the 323 notices published no selection criteria in the notice at all: each one says they sit in the procurement documents or the ESPD. That is page fifty. This version reads the rule when the notice itself publishes it, and reading the packs comes next. Of the 200 notices that do publish their criteria, the demo firm learns in one click per notice that 5 have a floor it can't meet alone, each with the sentence that sets it, and each of the other 195 names the open question to settle before anyone spends bid days on it.
What it does
A capture command asks TED's public search API for open IT notices (IT service and software codes, CPV 72 and 48) that buyers in the Netherlands, Belgium and Germany published in the last 14 days. For every lot, a part of a tender with its own criteria, that publishes its selection criteria, Nemotron 3 Super reads the clauses and returns typed requirements as JSON, each with a verbatim quote. Code then looks for every quote in the clause it came from, word for word after spacing, line breaks, hyphens and curly quote marks are evened out, refuses the ones it can't verify, and parses each amount, count and year out of the verified quote, never out of the model's own fields.
Then code compares those requirements with the firm's profile, inside the visitor's browser when it's their own firm, and every lot gets one of three answers: "Go", "Not met alone" or "Ask first". A fourth, "No-go", is reserved for a rule no partner can fix, and this version doesn't give it yet. The clause that decides is quoted right under the answer, with its language, its criterion code and a link to the notice on TED.
The model runs at capture time. The capture made 225 calls to Token Factory on 22 October, each recorded with its response id and usage, and the site serves what that run recorded, so opening a page doesn't call the model. The firm profile stays in the browser.
The answer a small firm actually gets

Notice 713597-2026 is a German federal framework contract. It asks for a net turnover of EUR 1,400,000 a year in the field of the contract, over the last three years. The demo firm made EUR 1,090,000, 1,210,000 and 1,240,000. The buyer coded the floor as an average, while its German text says each year, and the demo firm falls short either way: an average of EUR 1,180,000, a best year of EUR 1,240,000. So the lot reads "Not met alone", and the page explains that Article 63 lets another firm lend that turnover or bid jointly (in Germany the same rule is § 47 VgV). That's the first call a bid lead needs: not on your own. The page leaves the reference clause, a comparable contract the buyer asks to see, for the firm to judge, so the partner to look for is one that has done that kind of work.
What it refuses

Every reading on the site is model-written and labelled that way, and every quote has to survive the check. On 22 October the model gave 1,865 quotes. Code verified 1,789 of them against the source and refused 76 (the run record lists them as rejected), about one in 25. The check proves the words are the tender's own. It does not prove the model read them right, and nothing in this version measures that yet. The answer key under "What comes next" is the plan for it.
Notice 699142-2026 shows why the check exists, and also what it costs. Its staff criterion asks for at least 3 project managers, 5 developers and testers and 3 UX designers, with each role name in double quotes. The model copied all three lines but switched the double quotes to single ones, so none of its quotes matched, and the criterion shows as "Not read" instead of a count. Here the numbers were actually right, and a looser match would have kept them. I'd still rather show "Not read" than a figure nobody can trace back to the tender.
What I learned about Nemotron on Token Factory
Before building the model step, I ran a capped test of the NVIDIA models on my Token Factory account on 15 October, with real German, Dutch and French clauses. Three things changed the design.
Thinking is on by default, and it costs. With thinking on, one German lot used 4,101 reasoning tokens, 22.4 seconds and USD 0.00532. With enable_thinking: false in chat_template_kwargs, the same lot took 6.1 seconds and USD 0.00181 and still came back as valid JSON. A Dutch lot with thinking on spent its whole 8,000-token budget thinking and returned no answer at all. The capture runs with thinking off, and the run record shows 0 reasoning tokens.
The server did not enforce the JSON schema. No NVIDIA model on the account carries the JSON-mode tag, and one French reply broke JSON with a raw tab character copied straight out of the tender. So every reply is validated with Zod, a raw tab becomes a space before parsing, and a reply that fails gets one repair retry with the validation errors in the prompt.
Super quoted more exactly than the cheaper model listed in the EU, in a small test. With thinking off, Nemotron 3 Super found all 24 of its quotes word for word in German and Dutch, over two capped runs. Nemotron 3.5 Lightning, listed in eu-north1 in Finland at a fifth of Super's input price, misquoted 3 of its 24, in Dutch and French, under that day's check, and 2 under the one the product now runs. It also read a German "turnover in this field" clause as general turnover while quoting it exactly, a misreading the quote check alone would never catch.
Code catches that one another way: the kind of figure comes from the criterion code the buyer chose, and a reading whose kind disagrees with that code isn't compared. Twenty-four quotes per model is a small sample, enough to choose a model for this build and not to rank the two in general. So the model step uses Super, listed only in us-central1, and sends it public tender text only, never a firm's profile.
The full read on 22 October covered 288 lots in 225 calls: 293,177 tokens in, 208,761 out, USD 0.275838 at the list price read on 15 October. That's under a tenth of a US cent per lot. The whole run took 22 minutes, nearly all of it model calls and web searches: 390 of the 395 TED notices were already in the capture's cache.
Where Tavily fits
Tavily gives a bid lead somewhere to look next: tender pages found under the buyer's name. The capture ran one Tavily basic search for each of the 200 notices with criteria in the notice, on the lead buyer's name plus fixed words for tenders, awards and IT services in the buyer's language: 200 searches, 200 credits. Code keeps a result only when its title or address carries a word that tender and award pages use, or a tender portal's name. That kept 658 of the 1,000 results and gave 173 of the 200 notices a list, shown apart in "Tender pages from a web search for this buyer" as unchecked pages that never change the answer: notice 699958-2026 lists four. A tender word doesn't prove a page is this buyer's, and the panel says so. For 713597-2026 my query brought back five pages about Florida's time zone, each scored near zero by Tavily itself, so its panel reads "No tender pages found by a web search for this buyer."
Why not the tools that already exist
In September I read the pages of 12 tender tools sold in the Netherlands, Belgium and Germany, plus TenderNed's alert profile and a discovery-only lead service. Several check eligibility, and at least three cite the source clause, so a quote on its own is nothing new. Discovery is free on TenderNed, the Dutch portal, and on TED itself, but neither tells you whether you qualify. Where the tools differ is the order of things:
| The tools I read (their own pages, September 2026) | Pagefifty |
|---|---|
| An account, a profile or an upload before the first answer | A worked example on the first click, and your own profile kept in your browser: no account, nothing uploaded |
| A fit score or a count of criteria met, such as "36/41 erfüllt" or "8 / 10 Anforderungen erfüllt" | The one clause that decides, quoted and underlined |
| Mostly one country each, NL or DE | Dutch, Belgian and German buyers in one list, read where the notice publishes its criteria |
| No page says how a quote is checked | Each quote verified word for word by code, or refused |
What it does not do yet
Across all 323 notices the demo firm gets 5 "Not met alone" and 318 "Ask first": the 195 above, and the 123 with no criteria in the notice. Each "Ask first" names the open question instead of guessing. None reads a clean "Go", because a "Go" needs every criterion read and met. Each lot counts under the first open question it hits, so a notice sits in one group only:
- 132 need a figure or a judgment only the firm has, such as whether a reference counts as comparable work.
- 125 have nothing open but the documents. 123 of them publish no selection criteria in the notice at all: their criteria sit in the procurement documents or the ESPD, which this version does not read.
- 39 hold, as their first open question, a criterion this version shows but does not compare yet, insurance cover for example.
- 14 have a gap where it isn't settled whether another firm may close it.
- 5 have a criterion the code marks "Not read".
- 3 have lots that ask first for different reasons.
Counted by what they hold rather than by first question, 169 of the 323 name the procurement documents or the ESPD as a source of their criteria. The gap falls hardest on Dutch and Belgian buyers: 19 of their 114 notices carry criteria in the notice, and only 1 of the 65 from Dutch buyers, against 181 of the 209 from German buyers. Today Pagefifty helps most when a Dutch or Belgian firm looks across the border at German tenders, as in the example above.
What else it does not do:
- It reads the notice, not the document pack, so the page fifty this product is named after stays unread wherever a notice puts its criteria there. Reading the packs of Germany's DTVP portal and of TenderNed was cut in October to make the deadline, though both served packs with no account when I tested them in September.
- There is one live model run so far. Two more would show how much the model's reading and its 76 refusals vary between runs.
- The capture covers IT notices from three countries published in the 14 days before it, and only tenders on TED, where tenders above the EU thresholds must be published. Most smaller national tenders appear only on national portals such as TenderNed.
- TED listed 395 notices for that search, and 72 were left out, each named with its reason in the capture's README: 66 close by the hackathon's 30 October cutoff or have no deadline, 4 give a deadline's date and time in different offsets across the 25 October clock change, and 2 couldn't be read as published.
- The demo firm is invented.
- The model is listed only in us-central1, a US region, because the model listed in the EU misquoted more, and only public tender text goes there.
- It is not legal advice: it points at the clause, and the decision stays with you.
One thing that went wrong during the build: the final capture's first live run on 22 October wrote nothing, because 4 new notices straddled the 25 October clock change and my XML parser refused them as malformed. They are now left out by name, and the run that followed that morning is the one on the site.
What comes next: read the document packs, put the answer on each card of the tenders list, run the capture twice more, pin the buyer search to public tender portals with Tavily's include_domains, and score the Dutch read against a native-speaker answer key of about 100 clauses.
Accessibility
Every page comes in Light, Dark and Device themes, and every answer carries an icon and a word, never colour alone. On 24 October an automated axe audit of the deployed code's build found 0 violations on 36 audited pages: 16 routes in Light and Dark, the two example pages above among them, and two list pages again at phone width. The target is WCAG 2.2 AA, and an automated audit checks only part of it.
Evidence
LIVE RUN: measured on the real run. LOCAL BUILD: measured on a local build of the deployed code. FIXTURE: proven by a committed test. NOT RUN: not done yet. Every path is in the repository.
| Claim | State | Proof | Date |
|---|---|---|---|
| 323 notices checked, 288 lots in 200 notices read for USD 0.275838 at list price | LIVE RUN | examples/2026-10-22/run.json (reading.tokens and reading.prices) and readings.json |
2026-10-22 |
| 225 Token Factory calls, each with its response id and usage | LIVE RUN | run.json metered.responses, client src/lib/capture/token-factory.ts |
2026-10-22 |
| Every call answered on its first attempt | LIVE RUN | run.json: 225 Token Factory attempts and 225 responses, all first reads and no repair retry (a retry is recorded as its own chat-repair call, src/lib/capture/model-read.ts), and reading.lots notRead 0 |
2026-10-22 |
| 1,789 quotes verified, 76 refused | LIVE RUN | the run record's tally, run.json reading.quotes, and readings.json; shown case: 699142-2026 criterion 6 |
2026-10-22 |
| Thinking off, 0 reasoning tokens | LIVE RUN | run.json: reading.thinking false, and 225 responses with 0 reasoning tokens; shown on "How the AI is used" |
2026-10-22 |
| Demo firm: 5 "Not met alone", 318 "Ask first" | LIVE RUN | examples/2026-10-22/figure.json |
2026-10-22 |
| 200 Tavily searches for 200 credits | LIVE RUN | run.json search, and searches.json |
2026-10-22 |
| 658 of 1,000 search results listed, 27 notices with none | FIXTURE | src/lib/tenders/tender-web-page.test.ts (searches.json keeps all 1,000) |
2026-10-23 |
| Numbers compared by code, never by the model | FIXTURE | src/lib/core/compare.ts and compare.test.ts |
2026-10-23 |
| No profile value is sent to the server | FIXTURE | .dependency-cruiser.cjs rule no-server-reaches-profile (run by npm run gate), and scripts/e2e/canary.devbrowser.js in npm run test:e2e, which finds no typed profile value in any request or in the Worker's log |
2026-10-23 |
| 0 accessibility violations on 36 audited pages | LOCAL BUILD | npm run a11y:live on a build of the deployed commit's product code (233170b, with only tests and docs added), served locally by wrangler dev |
2026-10-24 |
| Document packs read | NOT RUN | cut in October | |
| Headline figure over three runs | NOT RUN | one run so far; two more would show how much the reading varies |
The run's files were committed within seven minutes of its end (8f7bfee to 8856e3f) and have not changed since, except figure.json, written again from the same readings (acc605e).
Built with
Nebius Token Factory, NVIDIA Nemotron 3 Super (nvidia/nemotron-3-super-120b-a12b), Tavily Search API, the TED Search API, SvelteKit, Svelte 5, TypeScript, Cloudflare Workers, Zod, fast-xml-parser and Vitest.
Built With
- cloudflare-workers
- fast-xml-parser
- nebius-token-factory
- nvidia-nemotron-3-super
- svelte
- sveltekit
- tavily
- ted-search-api
- typescript
- vitest
- zod
Log in or sign up for Devpost to join the conversation.