| Tokens reported | 1,114,540,355 |
|---|---|
| By member | Yanika 556M, Etienne 387M, Kyle 83M, Praveen 77M |
| Spend reported | $1,158.33 |
| Models named | GLM-5.2 (devs) and Qwen3 (app), per the same document |
Source: Tokens_Usage.docx — per-member table. These are the pod's own figures, not measurements by this assessment. Cap: €1,500 per pod.
| Hours stated | 299.0 h |
|---|---|
| Source | worklog_by_week.csv (Jira export), 5 people, weeks 33-36 |
| Per person | Yanika 77h, Duncan 70h, Kyle 65h, Praveen 57h, Etienne 30h |
| Above the 45 h/person allowance | Duncan +26h, Kyle +20h, Praveen +12h, Yanika +32h |
| Commits | no history in the artifact |
Submitted as GitLab source exports with no .git, so no commit history, author records or timestamps exist. Nothing in the artifact can corroborate or contradict the stated hours.
A commit is not an hour and a commit count is not effort. This bounds when work happened, not how long it took, and no score is derived from it.
The most complete prompt record of the trial, and most of it is verbatim. Five workstreams each left artifacts in their own working style: the FE series is day-numbered (Day 1-12) with real API schemas, polling rules and navigation contracts, so you can watch the mock spec harden into an integrated product; Kyle's backend log interleaves prompts with pasted stack traces and candid margin notes about what the model got wrong and what he replaced by hand, which is exactly the kept-vs-redone evidence the charter asks for; QA submitted agent definitions, skills and 7.2MB of raw OpenCode session JSON that confirms the work ran on the self-hosted GLM-5.2 proxy. The reusable core (the Day-1 product spec, reused verbatim by QA as test-plan input; the QA healer/planner agents) would transfer to another team. Points off because the 120KB Etienne dump is unfiltered session chatter that buries its good material, the DevOps file is paraphrase rather than verbatim, and coverage thins after ~24 Aug.
submissions/pod1-prove-it/docs/judge-pack/AI Prompts/Kyle's Prompts/Backend Prompts.txtsubmissions/pod1-prove-it/docs/judge-pack/AI Prompts/FE Prompts/Day 10 - ClientApplicationPrompt - DispatchCampaigns.txtsubmissions/pod1-prove-it/docs/judge-pack/AI Prompts/Etienne Prompts/Prompts/prompts.mdAssessed separately from the twelve categories: the trial's question was how each pod worked with models, and the prompts are the record of that.
Things a reader would want to know. Not findings against the submission and not scored — questions, oddities and loose ends.
submissions/pod1-prove-it/docs/judge-pack/AI Prompts/Etienne Prompts/Prompts/prompts.mdsubmissions/pod1-prove-it/docs/judge-pack/AI Prompts/FE Prompts/Day 2 - MockClientApplicationPrompt - GoogleAI.txtsubmissions/pod1-prove-it/docs/judge-pack/AI Prompts/DevOps - Promts/DevOps Prompts.txtsubmissions/pod1-prove-it/docs/judge-pack/AI Prompts/Kyle's Prompts/Backend Prompts.txtsubmissions/pod1-prove-it/docs/judge-pack/AI Prompts/Etienne Prompts/Prompts/Readme.mdsubmissions/pod1-prove-it/docs/judge-pack/AI Prompts/QA Prompts Skills and Agents/OpenCode Session 24-08/| Repository | GitLab source exports, 5 repos (no git history) + 158-file judge pack |
|---|---|
| Received | repos 31 Aug 11:20 CEST · documentation pack 31 Aug 12:03 CEST |
Unchanged: the code is what it was. Mechanisms for A-F are present and the app runs, but the headline refusal property fails at the boundary: the AGREE gate lives only in the SPA (sms-campaign-mockup/src/pages/MessagesPage.tsx:123 canApprove), while backend POST /dispatch (ngaige/api/routes/dispatch.py:150) has no approval check and no auth dependency; I seeded a session with no user and dispatched a campaign. The new pack sharpens rather than softens this: Consolidated_Decision_Register.md section 2 states 'Campaign approval and SMS dispatch require authentication', a requirement the backend does not implement. Per-client Sender ID remains absent (now explicitly listed in section 7.4, 'No Sender ID registration or selection'), consent remains asserted-by-upload (register section 7: uploads 'treated as a consented recipient list'), and F still lacks inbound STOP-keyword capture.
Move the approval gate server-side: require an explicit approved-by-user flag and authentication on POST /dispatch, and reject dispatch when the campaign has not been approved by the session's logged-in user, which is what your own decision register already says the system requires.
C and F are refusal properties — the system must decline to do something. A demo can look perfect with the mechanism absent, so these are probed adversarially rather than asked about.
Unchanged in substance: a single-host modular-monolith FastAPI app serving two SPAs, LiteLLM as the AI boundary, background pollers for dispatch status and Telegram; defensible for a fifteen-day trial. The decision register now documents the rationale behind the load-bearing choices (Marketing Agent vs orchestrator separation, LiteLLM abstraction so the model can change without app changes, SQLite as a deliberate trial choice with the limitation stated), which confirms the choices were deliberate but does not change what was built.
Document the intended production hardening path for the two trial choices you already flag (SQLite to Postgres, and where role-based Client/Back-Office separation would attach) so the modular-monolith boundaries survive that migration.
Novelty is not a virtue here. Boring and correct beats clever and unexplained.
Unchanged: typed SQLAlchemy 2.0 async style, consistent router-per-resource layout, conventions in AGENTS.md; a new engineer could work here. Against that: _get_authenticated_user_id is copy-pasted across dispatch.py, stop.py and user.py; the opted-out sync block is duplicated in auth.py (twice) and contacts.py; errors surface via print() with no logging framework. The judge pack adds context on how the code was produced (screen-by-screen bounded prompts, manual fixes where the model produced 'slop') but no new code.
Lift the duplicated authenticated-user lookup and the opted-out-sync block into ngaige/api/dependencies.py so opt-out enforcement has one definition rather than three drifting copies.
Volume earns nothing. A small codebase that does the six things beats a large one that does four.
Raised from 4. The pack supplies what the repos could not: a final Playwright HTML report (docs/judge-pack/Testing/latest-ngaige-test-report/, 203MB with traces, videos and AI failure analyses) matching the submission document's recorded run of 117 tests, 112 passed, 3 failed, 2 skipped (~95.7%), plus a tests HLD and a QA agent flow. That proves the suite really ran against the deployed app with an honest pass/fail record. The core critique stands: no test proves a refusal property at the API boundary; nothing asserts that unapproved or unauthenticated dispatch is rejected (it is not), and nothing opts a number out, dispatches again, and asserts exclusion. The suite still targets the live host and could not be run here.
Add a backend test that POSTs /dispatch on an unapproved campaign and asserts a 4xx, and one that opts a number out, generates messages, dispatches, and asserts that number received nothing.
Coverage percentage is not read. A single test that proves STOP excludes on the next send is worth more than 80% line coverage.
Raised from 5. The API still boots clean from its README (uv sync, uv run python main.py, migrations auto-run, simulation mode). The previously missing top-level runbook now exists in minimal form: 'Prove-it-Pod - Installation Guidelines.pdf' gives the full-stack path (envbuilder compose, Nexus registry, cert placement, 'docker compose --env-file .env.demo up -d traefik haud-ngaige-app'). It is one page, presumes access to their Nexus and GitLab, does not document environment variables beyond pointing at .env.demo, and could not be exercised from here, so it closes the gap on paper rather than demonstrably.
Expand the installation page with the required environment variables (LiteLLM endpoint, Auth0, Twilio) and a variant that does not depend on the private Nexus registry, so a HAUD engineer outside your network can stand the stack up.
This is scored by doing it. The result is binary and unkind: either the written steps produced a running system or they did not.
Raised from 6. The seven-point submission document scored as absent now exists (NGAIGE_Delivery_Acceptance_Evidence_Assessment.md) with all seven sections, alongside the HLD, a tests HLD, infra info, installation guidelines and the decision register; the handover surface is now real. It is weakened by unfinished edges: section 3 lists AR-01..13 but never marks them Met/Partially Met/Not Met, section 5's reproduction guide has 'TBD' for test data, accounts and expected results, template text survives ('Complete this section from the submitted repository'), and the section 9 checklist ticks items the document does not actually contain (commit SHA, exact acceptance mapping).
Finish the acceptance mapping in section 3 (each AR marked Met/Partial/Not Met with the code path and reproduction step) and replace the TBD fields, so the document delivers what its own checklist claims.
The bar is the client-bound mainline: would you hand this to someone who has never met the authors?
Raised from 4, the largest mover. The pack contains a genuine working record across five workstreams: FE prompts day-numbered 1-12 showing the screen-by-screen API-integration method, Kyle's backend log with explicit kept-vs-redone annotations ('it generated a lot of slop for the middleware... I replaced it manually with a working one-liner'), Etienne's timestamped OpenCode extraction (31 sessions, 220 prompts, extracted 28 Aug), DevOps prompt narratives including debugging iterations, QA agent/skill definitions with OpenCode session JSON exports, and per-member per-day token tables (1.2B tokens total). The method the decision register describes (bounded changes, review, manual fixes where cheaper than reprompting) is visible in the artifacts. Held below solid-plus by the explicit exclusion of DevOps Claude Code usage from the token document, which leaves the AI-usage record incomplete, and by the FE logs being curated final prompts rather than transcripts.
Include the Claude Code usage record (even as a summary of sessions and what they produced) and one or two full transcripts per workstream, so the record covers everything the pod used rather than the metered subset.
This is the whole point of the trial. A pod that shipped well but cannot show how it used AI has answered the wrong question.
Raised from 3, the category most changed. What was 'no journal, no decision log, no prompt log' is now 14 daily meeting minutes (11-28 Aug, AI-generated from meeting transcriptions per MeetingMinutesPrompt.txt, substantive: progress, blockers with owners, decisions, QA findings), a consolidated decision register separating decisions from proposals and open questions, day-numbered prompt logs, and Jira worklogs. This is not the exact rule-6 artifact: the kept/redone record is patchy outside Kyle's notes, impediments carry owners but not time-lost, and 'one thing we'd prompt differently' appears nowhere. Contemporaneity cannot be proven, since all 158 files are dated 31 Aug 10:02 (the zip time) and there is no git history, but internal dating (minutes dated per day, Etienne's extraction stamped 28 Aug) and the natural grain of the content read as records kept during the build and consolidated at the end.
Keep the rule-6 fields as a literal per-day table (drove / kept / redone-and-why / impediment with time lost / prompt-differently) alongside the minutes, and export it from a timestamped system so cadence is provable.
Entries dated across fifteen days read differently from fifteen entries committed on the last afternoon. The git history shows which.
Raised from 6. The self-assessment surface is now broad and genuinely unflattering: section 7 lists limitations across nine areas, Issues.docx adds a bug register, the section 8 LLM assessment flags its own weak evidence (missing acceptance traceability, unreproducible steps), and the 20 Aug minutes record that prompt injection succeeded and a fake medical-claim campaign was accepted, which few teams would put in front of judges. Two things cap it: neither of the highest-severity findings is disclosed anywhere in the pack (the unauthenticated /dispatch endpoint and the committed credentials), and the decision register affirmatively asserts a property the code does not have ('Campaign approval and SMS dispatch require authentication'). Read together this is an intent-verification gap, the pod stating what it believed rather than what it checked, not concealment, but it means the self-assessment is honest about what they knew and wrong about what they didn't.
Verify the security-relevant claims in the decision register against the API before asserting them, and add the two missing findings (no server-side auth/approval on dispatch, committed credentials) to the known-issues register.
A submission that names its own gaps is more trustworthy than one that claims six of six. Overclaiming found by probe is scored here, and it is the most damaging single finding a submission can carry.
Unchanged: open-weight throughout and the sovereignty boundary holds; the product reaches models only via LiteLLM fronting self-hosted vLLM (Qwen3-VL-4B-Instruct for the app, GLM-5.2-W4A16 on RunPod for development). The pack's section 6 now documents this deliberately, and the register records real selection reasoning (vision routing, cost/startup/memory tradeoffs, refusing a late model switch as unnecessary risk) plus an honest sovereignty caveat (RunPod EU location is not legal sovereignty). The weakness stands: the app takes the first model LiteLLM lists rather than pinning per task.
Pin an explicit model per task (chat, contact extraction, SMS generation) instead of taking the first model LiteLLM returns, so a routing change on the proxy cannot silently swap the model your product depends on.
Newest is not best. The scored question is fit and boundary, not leaderboard position. A pod that ran a mid-tier open model well scores above one that reached for a frontier API it was not permitted to use. A rule-2 breach is a finding here regardless of how good the output was.
Raised from 4. The accounting the first pass could not close is now closed: Tokens_Usage.docx totals ~$1,158 (RunPod $1,138.33, Twilio $20) against the EUR 1,500 cap, sourced from the admin panel the pod built, with per-member per-day token tables (1.2B tokens, 1.19B prompt / 7.2M completion) and Jira worklogs by week and task. They knew where the money went. Two blemishes keep it from higher: DevOps Claude Code usage is explicitly excluded ('Which is excluded from this Doc'), so the record is complete in euros but not in usage, and the document contradicts itself on Praveen's total (76,875,200 in the member table vs 162,612,236 in the key-alias breakdown and day subtotals).
Reconcile the two Praveen totals and state the USD-to-EUR conversion against the cap, so the ledger is internally consistent and closes in the charter's currency.
Underspending is not virtue and overspending is not vice; an exhausted budget is a workflow finding, not a failure. What is scored is whether the pod knew where the money went and can show it. A pod that spent the full cap and can account for it scores above one that spent half and cannot.
Unchanged: the pack contains no code changes and discloses neither issue. Real-shaped secrets remain committed in tracked files (Twilio auth token, Telegram bot token, Auth0 client secret in README and envbuilder compose, LiteLLM keys, VM SSH password in .gitlab-ci.yml, Postgres password, RunPod API key, HF tokens), and the register's decision to reuse 'the same Twilio API credentials... for the hosted audit instance' compounds the exposure. POST /dispatch still requires no authentication or approval despite the register asserting it does; consent is still asserted by upload; role separation is absent (this one is disclosed). The sovereignty boundary being respected is what keeps this off the floor. No credential was tested against a live service.
Rotate every committed credential, move them to runtime secrets outside the repo, and put an authentication dependency plus an approved-campaign check on POST /dispatch before anything can be sent.
A campaign platform that leaks a recipient list or ignores an opt-out is not a product, whatever else it does well.
| Category | Item | Where | Note |
|---|---|---|---|
| acceptance | AGREE gate exists only in the SPA | repo/sms-campaign-mockup/src/pages/MessagesPage.tsx:123 | canApprove = agree.trim().toUpperCase() === 'AGREE' && hasEnoughBalance; this is the only place AGREE is enforced. The string 'AGREE to unlock Approve' is also baked into the shipped bundle repo/ngaige-api/frontend/dist/assets/index-Cox8hJco.js. |
| acceptance | Backend dispatch has no approval or auth check | repo/ngaige-api/ngaige/api/routes/dispatch.py:150 | dispatch_campaign_messages depends only on get_db and get_active_chat. No approval flag, no get_authenticated_user. I booted the app, seeded a session with user_id NULL, POSTed /api/dispatch with just the session cookie, and it returned {campaign_id, sent_count:1}. Re-confirmed against the same source after the judge pack arrived. |
| candour | Decision register asserts dispatch requires authentication; code does not enforce it | docs/judge-pack/Decision Logs - Meeting Minutes/Consolidated_Decision_Register.md (section 2) | 'Campaign approval and SMS dispatch require authentication, although the trial allowed users to progress through much of the creation journey before logging in.' The backend enforces no such requirement on POST /dispatch, and no document in the pack (section 7.1 known issues, Issues.docx) discloses the gap. Adjacent auth gaps (shared Auth0 tenant, no role separation, no email verification) are disclosed. |
| security | Committed live-shaped secrets, undisclosed in the pack | repo/ngaige-api/envbuilder/docker-compose.yml | NGAIGE_TWILIO_AUTH_TOKEN, NGAIGE_TELEGRAM_TOKEN, NGAIGE_OAUTH_CLIENT_SECRET inline; Auth0 secret also in README.md; VM_PASSWORD in .gitlab-ci.yml; LiteLLM key, 3x HF tokens and a Postgres password in ngaige-infra. Not mentioned anywhere in the 158-file judge pack; the register (section 12) additionally records reusing the same Twilio credentials for the audit instance. Presence and shape only; nothing tested against a live service. |
| documentation | Seven-point submission document now exists, with unfinished edges | docs/judge-pack/NGAIGE_Delivery_Acceptance_Evidence_Assessment.md | All seven sections present (delivered, acceptance mapping, evidence index, reproduction, models, known issues, LLM assessment). Section 3 lists AR-01..13 without Met/Not-Met marks; section 5 reproduction has TBD test data/accounts; section 9 checklist ticks items the document does not contain (commit SHA). |
| ai_usage | Prompt logs with kept-vs-redone annotations | docs/judge-pack/AI Prompts/Kyle's Prompts/Backend Prompts.txt | 53KB backend prompt log with inline outcome notes, e.g. 'it generated a lot of slop for the middleware that didn't work. I replaced it manually with a working one-liner.' FE prompts are day-numbered 1-12; Etienne's prompts.md is a timestamped OpenCode extraction (31 sessions, 220 prompts, extracted 2026-08-28); QA folder includes agent definitions and OpenCode session JSON exports. |
| efficiency | Full spend and token accounting, with one exclusion and one inconsistency | docs/judge-pack/Tokens_Usage.docx | ~$1,158 total (RunPod $1,138.33 + Twilio $20) vs EUR 1,500 cap; per-member per-day token tables totalling 1,200,277,391 tokens. Notes 'DevOps also had access to Claude Code, Which is excluded from this Doc.' Praveen's total is 76,875,200 in the member table but 162,612,236 in the key-alias breakdown and day subtotals. |
| process | Daily meeting minutes with real QA findings | docs/judge-pack/Decision Logs - Meeting Minutes/MeetingMinutes- 20.08.26.docx | Day 8 minutes record per-person progress, blockers with owners (mobile-testing VPN problem, BlueStacks workaround), and adversarial LLM findings: prompt injection succeeded, a fake medical-claim campaign was accepted, a phishing campaign was refused. Fourteen dated minutes span 11-28 Aug; MeetingMinutesPrompt.txt shows they were AI-generated from meeting transcriptions. |
| testing | Final Playwright execution report supplied | docs/judge-pack/Testing/latest-ngaige-test-report/ | 203MB Playwright HTML report with traces, videos, screenshots and AI failure-analysis attachments, matching the recorded final run of 117 tests / 112 passed / 3 failed / 2 skipped (~95.7%) stated in the submission document section 2.7. Run against the deployed host; not reproducible from here. |
| model_choice | Open-weight models behind LiteLLM/vLLM, now documented | repo/ngaige-infra/docker-compose.yaml:177 | vLLM serves Qwen/Qwen3.6-35B-A3B, Qwen/Qwen3-VL-4B-Instruct and zai-org/GLM-5.2; product reaches models only via LiteLLM. Judge-pack section 6 documents GLM-5.2-W4A16 (4xH200 on RunPod) as the dev model and Qwen3-VL-4B as the app model; the register records vision-routing and cost/availability reasoning. |
| deployability | One-page full-stack installation guide | docs/judge-pack/Prove-it-Pod - Installation Guidelines.pdf | Points at envbuilder, requires their Nexus registry (insecure-registries), cert placement under /opt/DOCKER_DATA/TRAEFIK, and gives the startup command 'docker compose --env-file .env.demo up -d traefik haud-ngaige-app'. Closes the missing-runbook gap on paper; not exercisable without access to their network. |
| deployability | API boots clean from README steps | repo/ngaige-api/README.md | uv sync then uv run python main.py started the app, auto-ran Alembic migrations, and served / (200) and /api/ping in simulation mode. Backend pytest: 11 passed. |
Raised by the assessment, not answered by it. Each is a thing a reader of the submission would reasonably ask.
Checks that could not run. Recorded as unverified, never counted as failures.