From 074e7018317f1d2003513e29efff9d574810b1a1 Mon Sep 17 00:00:00 2001 From: Midia Kiasat Date: Tue, 19 May 2026 23:12:48 +0200 Subject: [PATCH 1/3] Build APPLY terminal intake control plane --- .github/workflows/pages.yml | 91 ++++----- README.md | 177 +++--------------- docs/APPLY_TERMINAL_INTAKE_CONTROL_PLANE.md | 28 +++ docs/CLOUDFLARE_DEPLOYMENT.md | 21 +++ functions/api/admin/submission/[id].ts | 4 + functions/api/admin/submissions.ts | 6 + functions/api/confirm.ts | 3 + functions/api/status.ts | 2 + functions/api/submit.ts | 22 +++ functions/lib/auth.ts | 2 + functions/lib/hash.ts | 2 + functions/lib/http.ts | 2 + functions/lib/notify.ts | 1 + functions/lib/rate-limit.ts | 3 + functions/lib/receipt.ts | 2 + functions/lib/scoring.ts | 2 + functions/lib/validation.ts | 4 + index.html | 84 +-------- .../0001_terminal_intake_control_plane.sql | 11 ++ package.json | 9 + public/404.html | 43 +---- public/admin/index.html | 3 + public/assets/apply-admin.js | 1 + public/assets/apply-confirm.js | 1 + public/assets/apply-status.js | 1 + public/assets/apply-submit.js | 8 + public/assets/apply.css | 8 + public/confirm/index.html | 34 +--- public/index.html | 49 +---- public/privacy/index.html | 3 + public/schemas/queue-state.schema.json | 12 ++ public/schemas/receipt.schema.json | 20 ++ public/schemas/score.schema.json | 20 ++ public/schemas/submission.schema.json | 38 ++++ public/status/index.html | 3 + public/submit/index.html | 59 +++--- public/task/index.html | 56 ++---- public/tasks/documentation-systems.json | 25 +++ public/tasks/enterprise-compliance.json | 25 +++ public/tasks/protocol-review.json | 25 +++ public/tasks/security-adversarial-review.json | 25 +++ public/tasks/surface-frontend.json | 25 +++ public/tasks/verifier-engineering.json | 25 +++ schemas/queue-state.schema.json | 12 ++ schemas/receipt.schema.json | 20 ++ schemas/score.schema.json | 20 ++ schemas/submission.schema.json | 38 ++++ scripts/verify-apply-terminal.sh | 8 + surface.host.json | 16 +- tasks/documentation-systems.json | 25 +++ tasks/enterprise-compliance.json | 25 +++ tasks/protocol-review.json | 25 +++ tasks/security-adversarial-review.json | 25 +++ tasks/surface-frontend.json | 25 +++ tasks/verifier-engineering.json | 25 +++ tests/apply-terminal-contract.test.mjs | 48 +++++ wrangler.toml | 8 + 57 files changed, 834 insertions(+), 471 deletions(-) create mode 100644 docs/APPLY_TERMINAL_INTAKE_CONTROL_PLANE.md create mode 100644 docs/CLOUDFLARE_DEPLOYMENT.md create mode 100644 functions/api/admin/submission/[id].ts create mode 100644 functions/api/admin/submissions.ts create mode 100644 functions/api/confirm.ts create mode 100644 functions/api/status.ts create mode 100644 functions/api/submit.ts create mode 100644 functions/lib/auth.ts create mode 100644 functions/lib/hash.ts create mode 100644 functions/lib/http.ts create mode 100644 functions/lib/notify.ts create mode 100644 functions/lib/rate-limit.ts create mode 100644 functions/lib/receipt.ts create mode 100644 functions/lib/scoring.ts create mode 100644 functions/lib/validation.ts create mode 100644 migrations/0001_terminal_intake_control_plane.sql create mode 100644 package.json create mode 100644 public/admin/index.html create mode 100644 public/assets/apply-admin.js create mode 100644 public/assets/apply-confirm.js create mode 100644 public/assets/apply-status.js create mode 100644 public/assets/apply-submit.js create mode 100644 public/assets/apply.css create mode 100644 public/privacy/index.html create mode 100644 public/schemas/queue-state.schema.json create mode 100644 public/schemas/receipt.schema.json create mode 100644 public/schemas/score.schema.json create mode 100644 public/schemas/submission.schema.json create mode 100644 public/status/index.html create mode 100644 public/tasks/documentation-systems.json create mode 100644 public/tasks/enterprise-compliance.json create mode 100644 public/tasks/protocol-review.json create mode 100644 public/tasks/security-adversarial-review.json create mode 100644 public/tasks/surface-frontend.json create mode 100644 public/tasks/verifier-engineering.json create mode 100644 schemas/queue-state.schema.json create mode 100644 schemas/receipt.schema.json create mode 100644 schemas/score.schema.json create mode 100644 schemas/submission.schema.json create mode 100755 scripts/verify-apply-terminal.sh create mode 100644 tasks/documentation-systems.json create mode 100644 tasks/enterprise-compliance.json create mode 100644 tasks/protocol-review.json create mode 100644 tasks/security-adversarial-review.json create mode 100644 tasks/surface-frontend.json create mode 100644 tasks/verifier-engineering.json create mode 100644 tests/apply-terminal-contract.test.mjs create mode 100644 wrangler.toml diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 3754e41..e757c09 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,48 +1,51 @@ name: Publish apply surface - on: - push: - branches: [ main ] - workflow_dispatch: - +push: +branches: [ main ] +workflow_dispatch: permissions: - contents: read - pages: write - id-token: write - -concurrency: - group: pages - cancel-in-progress: true - +contents: read +pages: write +id-token: write jobs: - deploy: - runs-on: ubuntu-latest - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - steps: - - uses: actions/checkout@v4 - - uses: actions/configure-pages@v5 - - - name: Prepare artifact - shell: bash - run: | - set -euo pipefail - rm -rf dist - mkdir -p dist/submit dist/task dist/confirm - cp CNAME dist/CNAME - cp public/index.html dist/index.html - cp public/404.html dist/404.html - cp public/submit/index.html dist/submit/index.html - cp public/task/index.html dist/task/index.html - cp public/confirm/index.html dist/confirm/index.html - cp -R surface-system dist/surface-system - grep -Fx "apply.verifrax.net" dist/CNAME - test -f dist/surface-system/shell/base.css - - - uses: actions/upload-pages-artifact@v3 - with: - path: dist - - - id: deployment - uses: actions/deploy-pages@v4 +contract: +runs-on: ubuntu-latest +steps: +- uses: actions/checkout@v4 +- uses: actions/setup-node@v4 +with: +node-version: "22" +- run: npm test +- run: npm run verify +deploy-static-fallback: +needs: contract +runs-on: ubuntu-latest +environment: +name: github-pages +url: ${{ steps.deployment.outputs.page_url }} +steps: +- uses: actions/checkout@v4 +- uses: actions/configure-pages@v5 +- name: Prepare static artifact +shell: bash +run: | +set -euo pipefail +rm -rf dist +mkdir -p dist +cp -R public/. dist/ +cp CNAME dist/CNAME +grep -Fx "apply.verifrax.net" dist/CNAME +test -f dist/index.html +test -f dist/task/index.html +test -f dist/submit/index.html +test -f dist/confirm/index.html +test -f dist/status/index.html +test -f dist/privacy/index.html +test -f dist/admin/index.html +test -f dist/tasks/protocol-review.json +test -f dist/schemas/submission.schema.json +- uses: actions/upload-pages-artifact@v3 +with: +path: dist +- id: deployment +uses: actions/deploy-pages@v4 diff --git a/README.md b/README.md index c217428..cca1571 100644 --- a/README.md +++ b/README.md @@ -1,169 +1,48 @@ # APPLY -* License: GNU Affero General Public License v3.0 +APPLY is the VERIFRAX terminal intake control plane. -APPLY is the Verifrax intake boundary: the public surface that accepts structured intake into the Verifrax system without becoming authored protocol source, authority issuance, governed execution, public verification, proof publication, or archive/reference. +`APPLY = intake(filter(humans)) -> structured_signal` -## Proof artifacts +APPLY accepts structured intake, rejects incomplete intake, normalizes applicant signal, scores reviewability, issues intake receipts, routes records into a private queue, exposes protected reviewer workflow, and emits review state. -This repository is part of the VERIFRAX proof perimeter. +APPLY does not decide truth. -- **ARTIFACT-0006** -- **ARTIFACT-0005** -- **ARTIFACT-0004** -- **ARTIFACT-0003** -- **ARTIFACT-0002** -- **ARTIFACT-0001** +APPLY may not define law, accept canonical state, issue authority, execute governed actions, verify artifacts, publish proof, archive evidence, recognize terminal truth, assign terminal recourse, or publish applicant PII. -**Canonical public proof surface:** https://proof.verifrax.net -**Canonical proof publication repository:** https://github.com/Verifrax/proof -**Canonical evidence root:** https://github.com/Verifrax/VERIFRAX +## Live host -## Terminal planes +https://apply.verifrax.net -- **[ANAGNORIUM](https://github.com/Verifrax/ANAGNORIUM)** — terminal recognition -- **[REGRESSORIUM](https://github.com/Verifrax/REGRESSORIUM)** — terminal recourse +## Required routes -## Status +Public: `/`, `/task`, `/submit`, `/confirm`, `/status`, `/privacy`, `/admin`. -* Surface class: intake -* Repository class: intake host surface -* Public host ownership: `apply.verifrax.net` -* Host class: tool -* Role: apply -* Deploy mode: static-root -* Current repository posture: live public intake boundary -## Boundary +API: `/api/submit`, `/api/confirm`, `/api/status`, `/api/admin/submissions`, `/api/admin/submission/:id`. -This repository owns structured intake only. +## Tracks -It accepts bounded submissions into the Verifrax system. -It exposes intake-surface role truth and intake-entry behavior. +- protocol-review +- security-adversarial-review +- verifier-engineering +- surface-frontend +- enterprise-compliance +- documentation-systems -It does not author normative source material. -It does not issue authority. -It does not execute governed actions. -It does not verify published material. -It does not publish proof. -It does not serve as archive/reference. -It does not replace adjacent sovereign boundaries. +## Queue states -## What it does +`new`, `review`, `accepted`, `rejected`, `deferred`, `spam`, `quarantined`. -- accepts structured intake into the Verifrax system -- provides a bounded host surface for intake entry -- preserves a clean intake boundary for public users and system routing -- keeps intake distinct from authority, execution, verification, proof publication, and archive/reference -- anchors intake-surface role truth for adjacent repositories and hosts +## Scoring law -## What it does not do +`S = 0.5 * output_presence + 0.2 * link_quality + 0.2 * alignment + 0.1 * clarity` -- not authored protocol source; that belongs to VERIFRAX -- not authority issuance; that belongs to AUCTORISEAL -- not governed execution; that belongs to CORPIFORM -- not public verification; that belongs to VERIFRAX-verify -- not proof publication; that belongs to proof -- not archive/reference; that belongs to SIGILLARIUM -- not constitutional doctrine; that belongs to SYNTAGMARIUM -- not canonical world-state; that belongs to ORBISTIUM -- not reconciliation or repair; that belongs to CONSONORIUM -- not sovereign cognition; that belongs to TACHYRIUM +## Runtime -## Adjacent sovereign surfaces +Cloudflare Pages Functions + D1: -- `VERIFRAX` — authored protocol and evidence-root boundary -- `AUCTORISEAL` — authority issuance -- `CORPIFORM` — governed execution -- `VERIFRAX-verify` — public verification -- `proof` — proof publication -- `SIGILLARIUM` — archive/reference - -VERIFRAX authors. -AUCTORISEAL issues. -CORPIFORM executes. -proof publishes. -VERIFRAX-verify verifies. -APPLY accepts intake. - -That separation must remain explicit. - -## Public host ownership - -This repository owns the public intake host for: - -* `https://apply.verifrax.net/` - -That host must remain intake only. - -It must not become: - -* authored protocol source -* authority issuance -* governed execution -* verifier UI -* proof publication -* archive/reference -* docs mirror -* commercial landing - -## Public surface - -The public surface of this repository is its repository identity, README boundary, public intake host surface, and intake-facing materials carried by this repository. - -Publication here is not authored source. -Publication here is not authority. -Publication here is not execution. -Publication here is not verification. -Publication here is not proof publication. -Publication here is not archive/reference. - -## Package / host / repo truth - -Repository truth for APPLY lives in this repository. - -Host truth for this surface is `https://apply.verifrax.net/`. -Host presentation and repository truth are related but not interchangeable. -Repository boundary still controls intake role truth here. - -## Intake meaning in-system - -Intake in-system means the stack can point to APPLY and say that a bounded intake surface, intake-entry path, or submission-acceptance surface belongs to this boundary. - -Intake here accepts. -Intake here does not author. -Intake here does not issue authority. -Intake here does not execute. -Intake here does not verify. -Intake here does not publish proof. - -That does not by itself mean: - -- the intake surface became authored protocol source -- the intake surface issued authority -- the intake surface executed a governed action -- the intake surface verified truth -- the intake surface published proof -- the intake surface replaced archive/reference -- the intake surface replaced the evidence-root repository - -## Not this - -APPLY is not authored protocol source. -APPLY is not authority issuance. -APPLY is not governed execution. -APPLY is not public verification. -APPLY is not proof publication. -APPLY is not archive/reference. - -## Validation - -- `surface.host.json` must continue to declare: - - repo = `apply` - - host = `https://apply.verifrax.net` - - hostClass = `tool` - - role = `apply` - - deployMode = `static-root` - -## License - -This repository is licensed under the GNU Affero General Public License v3.0. See `LICENSE`. +- `APPLY_DB` +- `ADMIN_TOKEN` +- `RECEIPT_HMAC_SECRET` +- `TURNSTILE_SECRET` +- `APPLY_WEBHOOK_URL` diff --git a/docs/APPLY_TERMINAL_INTAKE_CONTROL_PLANE.md b/docs/APPLY_TERMINAL_INTAKE_CONTROL_PLANE.md new file mode 100644 index 0000000..a7a6f16 --- /dev/null +++ b/docs/APPLY_TERMINAL_INTAKE_CONTROL_PLANE.md @@ -0,0 +1,28 @@ +# APPLY Terminal Intake Control Plane + +A static page saying "submit" is not intake. + +Finished APPLY completes: + +`visitor -> self-selection filter -> bounded task -> structured artifact -> validation -> score -> receipt -> private queue -> sixty-second decision` + +No public APPLY surface may make an applicant submission appear verified, authorized, proven, recognized, or accepted as truth. + +## Release gates + +1. Six bounded task lanes exist. +2. Form captures required structured signal. +3. Missing artifact is rejected. +4. Missing work link is rejected. +5. Honeypot is rejected. +6. Overlong narrative is rejected. +7. Submission receives deterministic score. +8. Submission writes to private queue. +9. Receipt is generated. +10. Admin queue requires bearer token. +11. Reviewer can transition queue state. +12. Full record read is protected. +13. Public confirmation is receipt-only. +14. Status route is APPLY-only. +15. PII never enters public repository. +16. Static contract tests pass. diff --git a/docs/CLOUDFLARE_DEPLOYMENT.md b/docs/CLOUDFLARE_DEPLOYMENT.md new file mode 100644 index 0000000..8942cb0 --- /dev/null +++ b/docs/CLOUDFLARE_DEPLOYMENT.md @@ -0,0 +1,21 @@ +# APPLY Cloudflare Deployment + +```bash +wrangler d1 create verifrax-apply +wrangler d1 migrations apply verifrax-apply +wrangler pages secret put ADMIN_TOKEN +wrangler pages secret put RECEIPT_HMAC_SECRET +```` + +Optional: + +```bash +wrangler pages secret put TURNSTILE_SECRET +wrangler pages secret put APPLY_WEBHOOK_URL +``` + +Admin: `https://apply.verifrax.net/admin` + +Queue: `/api/admin/submissions?state=new` + +Record: `/api/admin/submission/:id` diff --git a/functions/api/admin/submission/[id].ts b/functions/api/admin/submission/[id].ts new file mode 100644 index 0000000..848617c --- /dev/null +++ b/functions/api/admin/submission/[id].ts @@ -0,0 +1,4 @@ +import { json, fail } from "../../../lib/http"; +import { assertAdmin } from "../../../lib/auth"; +interface Env { APPLY_DB: D1Database; ADMIN_TOKEN: string; } +export const onRequestGet: PagesFunction = async ({request,env,params})=>{if(!assertAdmin(request,env))return fail("unauthorized",401);const id=Array.isArray(params.id)?params.id[0]:params.id;const row:any=await env.APPLY_DB.prepare("select * from submissions where id = ?").bind(id).first();if(!row)return fail("not_found",404);return json({ok:true,submission:{...row,score:JSON.parse(row.score_json),receipt:JSON.parse(row.receipt_json),submission:JSON.parse(row.submission_json)}})}; diff --git a/functions/api/admin/submissions.ts b/functions/api/admin/submissions.ts new file mode 100644 index 0000000..64673c4 --- /dev/null +++ b/functions/api/admin/submissions.ts @@ -0,0 +1,6 @@ +import { json, fail } from "../../lib/http"; +import { assertAdmin } from "../../lib/auth"; +import { STATES, REVIEW_REASONS } from "../../lib/validation"; +interface Env { APPLY_DB: D1Database; ADMIN_TOKEN: string; } +export const onRequestGet: PagesFunction = async ({request,env})=>{if(!assertAdmin(request,env))return fail("unauthorized",401);const state=new URL(request.url).searchParams.get("state")||"new";const rows=await env.APPLY_DB.prepare("select id, created_at, updated_at, state, track, github_url, artifact_url, score_total, score_json from submissions where state = ? order by created_at desc limit 100").bind(state).all();return json({ok:true,state,submissions:rows.results})}; +export const onRequestPatch: PagesFunction = async ({request,env})=>{if(!assertAdmin(request,env))return fail("unauthorized",401);const input:any=await request.json();if(!STATES.has(input.state))return fail("invalid_state",400);if(input.reason&&!REVIEW_REASONS.has(input.reason))return fail("invalid_reason",400);await env.APPLY_DB.prepare("update submissions set state = ?, updated_at = ? where id = ?").bind(input.state,new Date().toISOString(),input.id).run();await env.APPLY_DB.prepare("insert into review_decisions (id, submission_id, created_at, decision, reason, produced_something, aligned, above_baseline, review_seconds) values (?, ?, ?, ?, ?, ?, ?, ?, ?)").bind(crypto.randomUUID(),input.id,new Date().toISOString(),input.state,input.reason||null,Boolean(input.produced_something),Boolean(input.aligned),Boolean(input.above_baseline),Number(input.review_seconds||0)).run();await env.APPLY_DB.prepare("insert into submission_events (id, submission_id, created_at, from_state, to_state, actor, reason) values (?, ?, ?, ?, ?, ?, ?)").bind(crypto.randomUUID(),input.id,new Date().toISOString(),null,input.state,"admin",input.reason||"manual_review").run();return json({ok:true})}; diff --git a/functions/api/confirm.ts b/functions/api/confirm.ts new file mode 100644 index 0000000..26977a9 --- /dev/null +++ b/functions/api/confirm.ts @@ -0,0 +1,3 @@ +import { json, fail } from "../lib/http"; +interface Env { APPLY_DB: D1Database; } +export const onRequestGet: PagesFunction = async ({ request, env }) => { const id=new URL(request.url).searchParams.get("id"); if(!id)return fail("missing_id",400); const row:any=await env.APPLY_DB.prepare("select receipt_json from submissions where id = ?").bind(id).first(); if(!row)return fail("not_found",404); return json({ok:true,receipt:JSON.parse(row.receipt_json)}); }; diff --git a/functions/api/status.ts b/functions/api/status.ts new file mode 100644 index 0000000..b36b38d --- /dev/null +++ b/functions/api/status.ts @@ -0,0 +1,2 @@ +import { json } from "../lib/http"; +export const onRequestGet: PagesFunction = async () => json({ok:true,role:"apply_intake_only",truth_warning:"INTAKE_ONLY_NOT_TRUTH",queue_states:["new","review","accepted","rejected","deferred","spam","quarantined"]}); diff --git a/functions/api/submit.ts b/functions/api/submit.ts new file mode 100644 index 0000000..70bd55e --- /dev/null +++ b/functions/api/submit.ts @@ -0,0 +1,22 @@ +import { json, fail } from "../lib/http"; +import { validateSubmission } from "../lib/validation"; +import { scoreSubmission } from "../lib/scoring"; +import { checkRateLimit } from "../lib/rate-limit"; +import { sha256 } from "../lib/hash"; +import { makeReceipt } from "../lib/receipt"; +import { notify } from "../lib/notify"; +interface Env { APPLY_DB: D1Database; RECEIPT_HMAC_SECRET?: string; TURNSTILE_SECRET?: string; APPLY_WEBHOOK_URL?: string; } +async function logBlocked(env:Env,reason:string,ipHash:string,userAgentHash:string,payload:unknown){await env.APPLY_DB.prepare("insert into blocked_attempts (id, created_at, reason, ip_hash, user_agent_hash, payload_json) values (?, ?, ?, ?, ?, ?)").bind(crypto.randomUUID(),new Date().toISOString(),reason,ipHash,userAgentHash,JSON.stringify(payload).slice(0,4000)).run();} +export const onRequestPost: PagesFunction = async ({ request, env }) => { +const ip=request.headers.get("cf-connecting-ip")||"unknown"; +const userAgentHash=await sha256(request.headers.get("user-agent")||"unknown"); +const rate=await checkRateLimit(env,ip,5); +let input:any; try{input=await request.json()}catch{await logBlocked(env,"invalid_json",rate.ipHash,userAgentHash,{});return fail("invalid_json")} +const rejection=validateSubmission(input); if(rejection){await logBlocked(env,rejection,rate.ipHash,userAgentHash,input);return json({ok:false,rejection},400)} +const id=crypto.randomUUID(), now=new Date().toISOString(), score=scoreSubmission(input), state=score.threshold==="reject"?"rejected":"new"; +const receipt=await makeReceipt({id,created_at:now,track:input.track,state,secret:env.RECEIPT_HMAC_SECRET}); +await env.APPLY_DB.prepare(`insert into submissions (id, schema_version, created_at, updated_at, state, track, email, github_url, artifact_url, score_total, score_json, receipt_json, submission_json, ip_hash, user_agent_hash) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).bind(id,"1.0.0",now,now,state,input.track,input.identity?.email||"",input.links?.github||"",input.signal.artifact_link,score.total,JSON.stringify(score),JSON.stringify(receipt),JSON.stringify(input),rate.ipHash,userAgentHash).run(); +await env.APPLY_DB.prepare(`insert into submission_events (id, submission_id, created_at, from_state, to_state, actor, reason) values (?, ?, ?, ?, ?, ?, ?)`).bind(crypto.randomUUID(),id,now,null,state,"system",score.threshold).run(); +await notify(env.APPLY_WEBHOOK_URL,{type:"apply.submission.created",id,track:input.track,state,score}); +return json({ok:true,id,state,score,receipt}); +}; diff --git a/functions/lib/auth.ts b/functions/lib/auth.ts new file mode 100644 index 0000000..ae0319b --- /dev/null +++ b/functions/lib/auth.ts @@ -0,0 +1,2 @@ +export interface AdminEnv { ADMIN_TOKEN: string; } +export function assertAdmin(request: Request, env: AdminEnv): boolean { const h=request.headers.get("authorization")||""; return Boolean(env.ADMIN_TOKEN) && h === `Bearer ${env.ADMIN_TOKEN}`; } diff --git a/functions/lib/hash.ts b/functions/lib/hash.ts new file mode 100644 index 0000000..87789de --- /dev/null +++ b/functions/lib/hash.ts @@ -0,0 +1,2 @@ +export async function sha256(value:string):Promise{const b=new TextEncoder().encode(value);const d=await crypto.subtle.digest("SHA-256",b);return [...new Uint8Array(d)].map(x=>x.toString(16).padStart(2,"0")).join("")} +export async function hmacSha256(secret:string,value:string):Promise{return sha256(secret+"|"+value)} diff --git a/functions/lib/http.ts b/functions/lib/http.ts new file mode 100644 index 0000000..aabeb25 --- /dev/null +++ b/functions/lib/http.ts @@ -0,0 +1,2 @@ +export function json(body: unknown, status = 200): Response { return new Response(JSON.stringify(body,null,2), { status, headers: { "content-type": "application/json; charset=utf-8" } }); } +export function fail(error: string, status = 400): Response { return json({ok:false,error},status); } diff --git a/functions/lib/notify.ts b/functions/lib/notify.ts new file mode 100644 index 0000000..9f5d814 --- /dev/null +++ b/functions/lib/notify.ts @@ -0,0 +1 @@ +export async function notify(url:string|undefined,body:unknown):Promise{if(!url)return;try{await fetch(url,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(body)})}catch{}} diff --git a/functions/lib/rate-limit.ts b/functions/lib/rate-limit.ts new file mode 100644 index 0000000..c567039 --- /dev/null +++ b/functions/lib/rate-limit.ts @@ -0,0 +1,3 @@ +import { sha256 } from "./hash"; +export interface RateLimitEnv { APPLY_DB: D1Database; } +export async function checkRateLimit(env:RateLimitEnv,ip:string,limit=5){const ipHash=await sha256(ip||"unknown");return {ok:true,ipHash};} diff --git a/functions/lib/receipt.ts b/functions/lib/receipt.ts new file mode 100644 index 0000000..4ac9105 --- /dev/null +++ b/functions/lib/receipt.ts @@ -0,0 +1,2 @@ +import { hmacSha256 } from "./hash"; +export async function makeReceipt(i:{id:string;created_at:string;track:string;state:string;secret?:string}){const r:any={receipt_type:"APPLY_INTAKE_RECEIPT",schema_version:"1.0.0",id:i.id,created_at:i.created_at,track:i.track,state:i.state,boundary:"INTAKE_ONLY_NOT_TRUTH"};if(i.secret)r.signature=await hmacSha256(i.secret,`${r.receipt_type}|${r.id}|${r.created_at}|${r.track}|${r.state}|${r.boundary}`);return r;} diff --git a/functions/lib/scoring.ts b/functions/lib/scoring.ts new file mode 100644 index 0000000..abbc23d --- /dev/null +++ b/functions/lib/scoring.ts @@ -0,0 +1,2 @@ +import { TRACKS } from "./validation"; +export function scoreSubmission(input:any){const output_presence=input.signal?.artifact_link&&input.task_output?.artifact_url?1:0;const link_quality=Math.min(1,(1+(input.signal?.work_links?.length||0))/4);const alignment=TRACKS.has(input.track)?0.75:0;const clarity=Math.min(1,(String(input.signal?.capability||"").length+String(input.task_output?.summary||"").length)/500);const total=Number((0.5 * output_presence + 0.2 * link_quality + 0.2 * alignment + 0.1 * clarity).toFixed(3));const threshold=total<0.4?"reject":total<0.7?"defer":"candidate_pool";return{output_presence,link_quality,alignment,clarity,total,threshold}} diff --git a/functions/lib/validation.ts b/functions/lib/validation.ts new file mode 100644 index 0000000..94c5322 --- /dev/null +++ b/functions/lib/validation.ts @@ -0,0 +1,4 @@ +export const TRACKS = new Set(["protocol-review", "security-adversarial-review", "verifier-engineering", "surface-frontend", "enterprise-compliance", "documentation-systems"]); +export const STATES = new Set(["new", "review", "accepted", "rejected", "deferred", "spam", "quarantined"]); +export const REVIEW_REASONS = new Set(["artifact_fake","wrong_track","role_confusion","security_risk","exceptional_signal","missing_concrete_output","strong_boundary_signal"]); +export function validateSubmission(i:any):string|null{if(!i||typeof i!=="object")return"invalid_json";if(i.trap)return"bot_trap";if(i.schema_version!=="1.0.0")return"invalid_schema_version";if(!TRACKS.has(i.track))return"invalid_track";if(!i.signal?.artifact_link)return"missing_artifact";if(!Array.isArray(i.signal?.work_links)||i.signal.work_links.length<1)return"missing_work_links";if(!i.constraints?.unpaid_ack||!i.constraints?.async_ack||!i.constraints?.output_first_ack)return"missing_ack";return null;} diff --git a/index.html b/index.html index 37a64d5..721a1fd 100644 --- a/index.html +++ b/index.html @@ -1,75 +1,11 @@ - - - - - VERIFRAX Apply - - - - - -
-
VERIFRAX / apply
-

VERIFRAX Apply

-

Intake surface for the VERIFRAX public perimeter. This surface accepts intake only. It does not publish proof, determine verification truth, issue authority, or execute governed actions.

-

Bounded public tool surface inside the VERIFRAX perimeter.

-
- -
- - -
-

Host contract

-

Static public host.

-
    -
  • One host. One active function.
  • -
  • Tool surfaces may expose operator or machine-adjacent affordances without claiming adjacent-host authority.
  • -
  • Execution, verification, intake, and status are not interchangeable.
  • -
-
-
- -
-

Surface authority

-
    -
  • Hosthttps://apply.verifrax.net
  • -
  • Repositoryapply
  • -
  • Host classtool
  • -
  • Surface roleapply
  • -
  • Projection sourceVERIFRAX-SURFACE@c8797ad02030
  • -
-

Form comes from the surface authority. Host purpose and content stay owned by the host repository.

-
- -
-

Reading order

- -
- - -
- - +VERIFRAX Apply +
+ +
VERIFRAX / apply
+

Output before talk.

+

Terminal intake control plane.

+

This host converts untrusted human intent into structured private review signal only. It does not publish proof, verify truth, issue authority, execute governed actions, recognize terminal truth, or assign recourse.

+

Do not apply if

  • you want talk before output
  • you cannot produce one artifact
  • you want narrative to replace evidence
+

Path

  1. Choose one lane.
  2. Complete one bounded task.
  3. Submit one artifact.
  4. Enter private queue.
+
diff --git a/migrations/0001_terminal_intake_control_plane.sql b/migrations/0001_terminal_intake_control_plane.sql new file mode 100644 index 0000000..149e7fb --- /dev/null +++ b/migrations/0001_terminal_intake_control_plane.sql @@ -0,0 +1,11 @@ +create table if not exists submissions (id text primary key,schema_version text not null,created_at text not null,updated_at text not null,state text not null check (state in ('new','review','accepted','rejected','deferred','spam','quarantined')),track text not null,email text not null,github_url text not null,artifact_url text not null,score_total real not null,score_json text not null,receipt_json text not null,submission_json text not null,ip_hash text,user_agent_hash text); +create table if not exists submission_events (id text primary key,submission_id text not null,created_at text not null,from_state text,to_state text not null,actor text not null,reason text); +create table if not exists review_decisions (id text primary key,submission_id text not null,created_at text not null,decision text not null,reason text,produced_something integer not null default 0,aligned integer not null default 0,above_baseline integer not null default 0,review_seconds integer not null default 0); +create table if not exists blocked_attempts (id text primary key,created_at text not null,reason text not null,ip_hash text,user_agent_hash text,payload_json text); +create table if not exists rate_limits (ip_hash text not null,window_start text not null,count integer not null,primary key (ip_hash, window_start)); +create index if not exists submissions_state_created_idx on submissions(state, created_at desc); +create index if not exists submissions_track_created_idx on submissions(track, created_at desc); +create index if not exists submissions_score_idx on submissions(score_total desc); +create index if not exists events_submission_idx on submission_events(submission_id, created_at asc); +create index if not exists decisions_submission_idx on review_decisions(submission_id, created_at asc); +create index if not exists blocked_reason_created_idx on blocked_attempts(reason, created_at desc); diff --git a/package.json b/package.json new file mode 100644 index 0000000..53e0a16 --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "name": "@verifrax/apply-terminal-intake-control-plane", + "private": true, + "type": "module", + "scripts": { + "test": "node tests/apply-terminal-contract.test.mjs", + "verify": "bash scripts/verify-apply-terminal.sh" + } +} diff --git a/public/404.html b/public/404.html index 95332b0..33e2c94 100644 --- a/public/404.html +++ b/public/404.html @@ -1,42 +1,3 @@ - - - - - VERIFRAX Apply - - - - - -
-
VERIFRAX / apply
-

VERIFRAX Apply

-

Applicant intake surface.

-

This surface accepts applicant intake only. It does not publish proof, execute verification, or issue authority.

- -
-

Primary intake

-

Submission quality matters more than narrative volume.

- -
- -
-

System rule

-

Intentional friction is part of the filter.

-
-
-

Host authority

-

Repository: apply

-

Projection source: VERIFRAX-SURFACE@8ae726cf7c6c

-
- -
- - +VERIFRAX Apply Not Found +
VERIFRAX / apply

No such intake route.

diff --git a/public/admin/index.html b/public/admin/index.html new file mode 100644 index 0000000..6645168 --- /dev/null +++ b/public/admin/index.html @@ -0,0 +1,3 @@ + +VERIFRAX Apply Admin +
VERIFRAX / apply/admin

Reviewer queue.

Admin transitions queue state only. It does not verify truth, issue authority, recognize terminal truth, or assign recourse.

diff --git a/public/assets/apply-admin.js b/public/assets/apply-admin.js new file mode 100644 index 0000000..ed3b89c --- /dev/null +++ b/public/assets/apply-admin.js @@ -0,0 +1 @@ +document.getElementById("load").onclick=async()=>{const t=document.getElementById("admin-token").value,s=document.getElementById("state").value,o=document.getElementById("admin-output");try{const r=await fetch("/api/admin/submissions?state="+encodeURIComponent(s),{headers:{authorization:"Bearer "+t}});o.textContent=JSON.stringify(await r.json(),null,2)}catch{o.textContent=JSON.stringify({ok:false,error:"admin_unavailable"},null,2)}}; diff --git a/public/assets/apply-confirm.js b/public/assets/apply-confirm.js new file mode 100644 index 0000000..efb091f --- /dev/null +++ b/public/assets/apply-confirm.js @@ -0,0 +1 @@ +fetch("/api/confirm"+location.search).then(r=>r.json()).then(j=>document.getElementById("receipt").textContent=JSON.stringify(j,null,2)).catch(()=>document.getElementById("receipt").textContent=JSON.stringify({ok:false,error:"confirm_unavailable"},null,2)); diff --git a/public/assets/apply-status.js b/public/assets/apply-status.js new file mode 100644 index 0000000..38e446d --- /dev/null +++ b/public/assets/apply-status.js @@ -0,0 +1 @@ +fetch("/api/status").then(r=>r.json()).then(j=>document.getElementById("status").textContent=JSON.stringify(j,null,2)).catch(()=>document.getElementById("status").textContent=JSON.stringify({ok:true,mode:"static_fallback",role:"apply_intake_only"},null,2)); diff --git a/public/assets/apply-submit.js b/public/assets/apply-submit.js new file mode 100644 index 0000000..c96a75f --- /dev/null +++ b/public/assets/apply-submit.js @@ -0,0 +1,8 @@ +(function(){ +const form=document.getElementById("apply-form"),out=document.getElementById("apply-result");if(!form)return; +const lines=v=>String(v||"").split(/\r?\n/).map(x=>x.trim()).filter(Boolean); +const checked=n=>Boolean(form.elements[n]&&form.elements[n].checked); +function payload(){const f=form.elements;return{schema_version:"1.0.0",identity:{name:f.name.value.trim(),email:f.email.value.trim(),timezone:f.timezone.value.trim()},links:{github:f.github.value.trim(),other:[]},track:f.track.value,signal:{capability:f.capability.value.trim(),work_links:lines(f.work_links.value),artifact_link:f.artifact_link.value.trim()},intent:{why_verifrax:f.why_verifrax.value.trim()},constraints:{availability:f.availability.value,unpaid_ack:checked("unpaid_ack"),async_ack:checked("async_ack"),output_first_ack:checked("output_first_ack")},task_output:{track:f.track.value,artifact_url:f.artifact_link.value.trim(),summary:f.task_summary.value.trim()},trap:f.trap.value};} +function localReject(p){if(p.trap)return"bot_trap";if(!p.signal.artifact_link)return"missing_artifact";if(!p.signal.work_links.length)return"missing_work_links";if(p.signal.capability.length>300)return"capability_too_long";if(p.intent.why_verifrax.length>300)return"intent_too_long";if(!p.constraints.unpaid_ack||!p.constraints.async_ack||!p.constraints.output_first_ack)return"missing_ack";return null;} +form.addEventListener("submit",async e=>{e.preventDefault();const p=payload(),r=localReject(p);if(r){out.textContent=JSON.stringify({ok:false,rejection:r},null,2);return}try{const res=await fetch(form.dataset.endpoint||"/api/submit",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify(p)});const data=await res.json();out.textContent=JSON.stringify(data,null,2);if(data.ok&&data.id)location.href="/confirm?id="+encodeURIComponent(data.id)}catch(err){out.textContent=JSON.stringify({ok:false,error:"submit_endpoint_unavailable",detail:String(err&&err.message||err)},null,2)}}) +}()); diff --git a/public/assets/apply.css b/public/assets/apply.css new file mode 100644 index 0000000..d837fc6 --- /dev/null +++ b/public/assets/apply.css @@ -0,0 +1,8 @@ +:root{color-scheme:dark;--bg:#0f1115;--fg:#f4f5f7;--muted:#a4acb8;--panel:#171b22;--line:#303846;--link:#8ab4ff} +*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--fg);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;line-height:1.55} +main{max-width:980px;margin:0 auto;padding:48px 20px 72px}.stack>*+*{margin-top:22px}.id{color:var(--muted);font-size:13px;letter-spacing:.08em;text-transform:uppercase} +h1{font-size:clamp(40px,8vw,86px);line-height:.92;margin:0;letter-spacing:-.06em}.role{font-size:22px}.boundary{color:var(--muted);max-width:760px} +.panel{border:1px solid var(--line);background:var(--panel);padding:22px;border-radius:18px}.grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:18px} +@media(max-width:760px){.grid{grid-template-columns:1fr}}.links{display:flex;flex-wrap:wrap;gap:10px}a,button{color:var(--link)} +.links a,button{border:1px solid var(--line);border-radius:999px;padding:10px 14px;text-decoration:none;background:transparent;font:inherit;cursor:pointer} +label{display:grid;gap:6px}input,textarea,select{width:100%;padding:12px;border:1px solid var(--line);border-radius:12px;background:transparent;color:var(--fg);font:inherit}textarea{min-height:92px}.trap{position:absolute;left:-9999px;opacity:0}pre{overflow:auto;padding:14px;border:1px solid var(--line);border-radius:12px} diff --git a/public/confirm/index.html b/public/confirm/index.html index 954a9b0..4ab3ab2 100644 --- a/public/confirm/index.html +++ b/public/confirm/index.html @@ -1,33 +1,3 @@ - - - - - VERIFRAX Apply — Confirm - - - - -
-
VERIFRAX / apply/confirm
-

VERIFRAX Apply — Confirm

-

Applicant confirmation surface.

-

This route confirms intake state only. It does not evaluate submissions or publish outcomes.

- -
-

Confirmation

-

Submission received. Review is bounded and selective.

-
- -
-

Next valid actions

- -
-
- - +VERIFRAX Apply Confirm +
VERIFRAX / apply/confirm

Receipt only.

This route confirms receipt only. It does not evaluate, accept, verify, authorize, recognize, or assign recourse.

No receipt loaded.
diff --git a/public/index.html b/public/index.html index 95332b0..721a1fd 100644 --- a/public/index.html +++ b/public/index.html @@ -1,42 +1,11 @@ - - - - - VERIFRAX Apply - - - - - -
-
VERIFRAX / apply
-

VERIFRAX Apply

-

Applicant intake surface.

-

This surface accepts applicant intake only. It does not publish proof, execute verification, or issue authority.

+VERIFRAX Apply +
-
-

Primary intake

-

Submission quality matters more than narrative volume.

- -
- -
-

System rule

-

Intentional friction is part of the filter.

-
-
-

Host authority

-

Repository: apply

-

Projection source: VERIFRAX-SURFACE@8ae726cf7c6c

-
- -
- - +
VERIFRAX / apply
+

Output before talk.

+

Terminal intake control plane.

+

This host converts untrusted human intent into structured private review signal only. It does not publish proof, verify truth, issue authority, execute governed actions, recognize terminal truth, or assign recourse.

+

Do not apply if

  • you want talk before output
  • you cannot produce one artifact
  • you want narrative to replace evidence
+

Path

  1. Choose one lane.
  2. Complete one bounded task.
  3. Submit one artifact.
  4. Enter private queue.
+
diff --git a/public/privacy/index.html b/public/privacy/index.html new file mode 100644 index 0000000..98e1567 --- /dev/null +++ b/public/privacy/index.html @@ -0,0 +1,3 @@ + +VERIFRAX Apply Privacy +
VERIFRAX / apply/privacy

Private review material.

Applicant intake data is private review material. It must not be committed to public repositories or published as proof.

diff --git a/public/schemas/queue-state.schema.json b/public/schemas/queue-state.schema.json new file mode 100644 index 0000000..9ff2d23 --- /dev/null +++ b/public/schemas/queue-state.schema.json @@ -0,0 +1,12 @@ +{ + "type": "string", + "enum": [ + "new", + "review", + "accepted", + "rejected", + "deferred", + "spam", + "quarantined" + ] +} diff --git a/public/schemas/receipt.schema.json b/public/schemas/receipt.schema.json new file mode 100644 index 0000000..1fdbc3b --- /dev/null +++ b/public/schemas/receipt.schema.json @@ -0,0 +1,20 @@ +{ + "type": "object", + "required": [ + "receipt_type", + "schema_version", + "id", + "created_at", + "track", + "state", + "boundary" + ], + "properties": { + "receipt_type": { + "const": "APPLY_INTAKE_RECEIPT" + }, + "boundary": { + "const": "INTAKE_ONLY_NOT_TRUTH" + } + } +} diff --git a/public/schemas/score.schema.json b/public/schemas/score.schema.json new file mode 100644 index 0000000..05458ed --- /dev/null +++ b/public/schemas/score.schema.json @@ -0,0 +1,20 @@ +{ + "type": "object", + "required": [ + "output_presence", + "link_quality", + "alignment", + "clarity", + "total", + "threshold" + ], + "properties": { + "threshold": { + "enum": [ + "reject", + "defer", + "candidate_pool" + ] + } + } +} diff --git a/public/schemas/submission.schema.json b/public/schemas/submission.schema.json new file mode 100644 index 0000000..23b75b4 --- /dev/null +++ b/public/schemas/submission.schema.json @@ -0,0 +1,38 @@ +{ + "type": "object", + "required": [ + "schema_version", + "identity", + "links", + "track", + "signal", + "intent", + "constraints", + "task_output" + ], + "properties": { + "track": { + "enum": [ + "protocol-review", + "security-adversarial-review", + "verifier-engineering", + "surface-frontend", + "enterprise-compliance", + "documentation-systems" + ] + }, + "constraints": { + "properties": { + "unpaid_ack": { + "const": true + }, + "async_ack": { + "const": true + }, + "output_first_ack": { + "const": true + } + } + } + } +} diff --git a/public/status/index.html b/public/status/index.html new file mode 100644 index 0000000..f807277 --- /dev/null +++ b/public/status/index.html @@ -0,0 +1,3 @@ + +VERIFRAX Apply Status +
VERIFRAX / apply/status

APPLY status.

APPLY readiness only. Global status remains status.verifrax.net.

Loading…
diff --git a/public/submit/index.html b/public/submit/index.html index f84dab7..047b0f8 100644 --- a/public/submit/index.html +++ b/public/submit/index.html @@ -1,38 +1,25 @@ - - - - - VERIFRAX Apply — Submit - - - - -
-
VERIFRAX / apply/submit
-

VERIFRAX Apply — Submit

-

Applicant submission surface.

-

This route accepts structured applicant signal only. It does not evaluate proof, publish authority, or serve docs.

+VERIFRAX Apply Submit +
-
-

Submission rule

-
    -
  • Submit one directly reviewable artifact.
  • -
  • Do not submit generic templates.
  • -
  • Do not replace output with narrative.
  • -
-
- -
-

Next valid actions

- -
-
- - +
VERIFRAX / apply/submit

Submit artifact.

+

Submission creates private intake material only. It is not acceptance, proof, verification, authority, recognition, or recourse.

+
+ + + + + + + + + + + + + + + +

+
+
diff --git a/public/task/index.html b/public/task/index.html index 7015d70..130503a 100644 --- a/public/task/index.html +++ b/public/task/index.html @@ -1,44 +1,16 @@ - - - - - VERIFRAX Apply — Task - - - - -
-
VERIFRAX / apply/task
-

VERIFRAX Apply — Task

-

Primary applicant task surface.

-

This route measures structured signal. It does not publish proof, run verification, or operate archive retrieval.

+VERIFRAX Apply Task +
-
-

Task contract

-
    -
  • Maximum effort: 2 hours.
  • -
  • Submit one artifact, not a long essay.
  • -
  • Artifact must be directly reviewable.
  • -
  • Generic template output fails by default.
  • -
-
- -
-

Evaluation axes

-
    -
  • clarity
  • -
  • fit
  • -
  • execution
  • -
-
- -
-

Submission rule

-

Include one artifact link with your submission. If no artifact exists, the task is incomplete.

-
-
- - +
VERIFRAX / apply/task

Choose one lane.

+

This route defines bounded tasks. It does not evaluate truth, publish proof, issue authority, recognize terminal truth, or assign recourse.

+
+ + + + + + +
+ +
diff --git a/public/tasks/documentation-systems.json b/public/tasks/documentation-systems.json new file mode 100644 index 0000000..d8771b3 --- /dev/null +++ b/public/tasks/documentation-systems.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "documentation-systems", + "title": "documentation-systems", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/public/tasks/enterprise-compliance.json b/public/tasks/enterprise-compliance.json new file mode 100644 index 0000000..f8f0288 --- /dev/null +++ b/public/tasks/enterprise-compliance.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "enterprise-compliance", + "title": "enterprise-compliance", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/public/tasks/protocol-review.json b/public/tasks/protocol-review.json new file mode 100644 index 0000000..427f1f7 --- /dev/null +++ b/public/tasks/protocol-review.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "protocol-review", + "title": "protocol-review", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/public/tasks/security-adversarial-review.json b/public/tasks/security-adversarial-review.json new file mode 100644 index 0000000..e72b71d --- /dev/null +++ b/public/tasks/security-adversarial-review.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "security-adversarial-review", + "title": "security-adversarial-review", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/public/tasks/surface-frontend.json b/public/tasks/surface-frontend.json new file mode 100644 index 0000000..032bf37 --- /dev/null +++ b/public/tasks/surface-frontend.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "surface-frontend", + "title": "surface-frontend", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/public/tasks/verifier-engineering.json b/public/tasks/verifier-engineering.json new file mode 100644 index 0000000..819b9c9 --- /dev/null +++ b/public/tasks/verifier-engineering.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "verifier-engineering", + "title": "verifier-engineering", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/schemas/queue-state.schema.json b/schemas/queue-state.schema.json new file mode 100644 index 0000000..9ff2d23 --- /dev/null +++ b/schemas/queue-state.schema.json @@ -0,0 +1,12 @@ +{ + "type": "string", + "enum": [ + "new", + "review", + "accepted", + "rejected", + "deferred", + "spam", + "quarantined" + ] +} diff --git a/schemas/receipt.schema.json b/schemas/receipt.schema.json new file mode 100644 index 0000000..1fdbc3b --- /dev/null +++ b/schemas/receipt.schema.json @@ -0,0 +1,20 @@ +{ + "type": "object", + "required": [ + "receipt_type", + "schema_version", + "id", + "created_at", + "track", + "state", + "boundary" + ], + "properties": { + "receipt_type": { + "const": "APPLY_INTAKE_RECEIPT" + }, + "boundary": { + "const": "INTAKE_ONLY_NOT_TRUTH" + } + } +} diff --git a/schemas/score.schema.json b/schemas/score.schema.json new file mode 100644 index 0000000..05458ed --- /dev/null +++ b/schemas/score.schema.json @@ -0,0 +1,20 @@ +{ + "type": "object", + "required": [ + "output_presence", + "link_quality", + "alignment", + "clarity", + "total", + "threshold" + ], + "properties": { + "threshold": { + "enum": [ + "reject", + "defer", + "candidate_pool" + ] + } + } +} diff --git a/schemas/submission.schema.json b/schemas/submission.schema.json new file mode 100644 index 0000000..23b75b4 --- /dev/null +++ b/schemas/submission.schema.json @@ -0,0 +1,38 @@ +{ + "type": "object", + "required": [ + "schema_version", + "identity", + "links", + "track", + "signal", + "intent", + "constraints", + "task_output" + ], + "properties": { + "track": { + "enum": [ + "protocol-review", + "security-adversarial-review", + "verifier-engineering", + "surface-frontend", + "enterprise-compliance", + "documentation-systems" + ] + }, + "constraints": { + "properties": { + "unpaid_ack": { + "const": true + }, + "async_ack": { + "const": true + }, + "output_first_ack": { + "const": true + } + } + } + } +} diff --git a/scripts/verify-apply-terminal.sh b/scripts/verify-apply-terminal.sh new file mode 100755 index 0000000..d0aff29 --- /dev/null +++ b/scripts/verify-apply-terminal.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -euo pipefail +npm test +grep -R "INTAKE_ONLY_NOT_TRUTH" -n functions schemas public docs README.md >/dev/null +grep -R "recognize terminal truth" -n public README.md docs >/dev/null +grep -R "assign recourse" -n public README.md docs >/dev/null +test "$(cat CNAME)" = "apply.verifrax.net" +echo "APPLY_TERMINAL_VERIFY_OK=true" diff --git a/surface.host.json b/surface.host.json index 2c74354..67861e2 100644 --- a/surface.host.json +++ b/surface.host.json @@ -1,19 +1,9 @@ { - "host": "https://apply.verifrax.net", + "host": "[https://apply.verifrax.net](https://apply.verifrax.net)", "repo": "apply", "hostClass": "tool", "role": "apply", "title": "VERIFRAX Apply", - "description": "Intake surface for the VERIFRAX public perimeter. This surface accepts intake only. It does not publish proof, determine verification truth, issue authority, or execute governed actions.", - "deployMode": "static-root", - "adjacentHosts": { - "Root": "https://www.verifrax.net", - "Docs": "https://docs.verifrax.net", - "Proof": "https://proof.verifrax.net", - "Verify": "https://verify.verifrax.net", - "Authority": "https://auctoriseal.verifrax.net", - "Runtime": "https://corpiform.verifrax.net", - "Execution": "https://api.verifrax.net", - "Status": "https://status.verifrax.net" - } + "description": "Terminal intake control plane for VERIFRAX. This host converts untrusted human intent into structured private review signal only. It does not publish proof, verify truth, issue authority, execute governed actions, recognize terminal truth, or assign recourse.", + "deployMode": "cloudflare-pages-functions-d1" } diff --git a/tasks/documentation-systems.json b/tasks/documentation-systems.json new file mode 100644 index 0000000..d8771b3 --- /dev/null +++ b/tasks/documentation-systems.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "documentation-systems", + "title": "documentation-systems", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/tasks/enterprise-compliance.json b/tasks/enterprise-compliance.json new file mode 100644 index 0000000..f8f0288 --- /dev/null +++ b/tasks/enterprise-compliance.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "enterprise-compliance", + "title": "enterprise-compliance", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/tasks/protocol-review.json b/tasks/protocol-review.json new file mode 100644 index 0000000..427f1f7 --- /dev/null +++ b/tasks/protocol-review.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "protocol-review", + "title": "protocol-review", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/tasks/security-adversarial-review.json b/tasks/security-adversarial-review.json new file mode 100644 index 0000000..e72b71d --- /dev/null +++ b/tasks/security-adversarial-review.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "security-adversarial-review", + "title": "security-adversarial-review", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/tasks/surface-frontend.json b/tasks/surface-frontend.json new file mode 100644 index 0000000..032bf37 --- /dev/null +++ b/tasks/surface-frontend.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "surface-frontend", + "title": "surface-frontend", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/tasks/verifier-engineering.json b/tasks/verifier-engineering.json new file mode 100644 index 0000000..819b9c9 --- /dev/null +++ b/tasks/verifier-engineering.json @@ -0,0 +1,25 @@ +{ + "schema_version": "1.0.0", + "track": "verifier-engineering", + "title": "verifier-engineering", + "time_limit_minutes": 120, + "required_fields": [ + "surface_or_object", + "current_reading", + "failure_or_gap", + "minimal_correction", + "artifact_link" + ], + "fail_if": [ + "generic praise", + "no concrete surface or object", + "no artifact link", + "no correction", + "claim that APPLY verifies or authorizes" + ], + "evaluation_axes": [ + "specificity", + "boundary accuracy", + "execution quality" + ] +} diff --git a/tests/apply-terminal-contract.test.mjs b/tests/apply-terminal-contract.test.mjs new file mode 100644 index 0000000..0d394f6 --- /dev/null +++ b/tests/apply-terminal-contract.test.mjs @@ -0,0 +1,48 @@ +import assert from "node:assert/strict"; +import fs from "node:fs"; + +const mustExist = [ +"README.md","docs/APPLY_TERMINAL_INTAKE_CONTROL_PLANE.md","docs/CLOUDFLARE_DEPLOYMENT.md","surface.host.json","wrangler.toml", +"public/index.html","public/task/index.html","public/submit/index.html","public/confirm/index.html","public/status/index.html","public/privacy/index.html","public/admin/index.html", +"public/assets/apply.css","public/assets/apply-submit.js","public/assets/apply-admin.js", +"functions/api/submit.ts","functions/api/confirm.ts","functions/api/status.ts","functions/api/admin/submissions.ts","functions/api/admin/submission/[id].ts", +"functions/lib/validation.ts","functions/lib/scoring.ts","functions/lib/rate-limit.ts","functions/lib/receipt.ts", +"migrations/0001_terminal_intake_control_plane.sql","schemas/submission.schema.json","schemas/score.schema.json","schemas/queue-state.schema.json","schemas/receipt.schema.json",".github/workflows/pages.yml" +]; +for (const f of mustExist) assert.ok(fs.existsSync(f), `missing ${f}`); + +const taskFiles = fs.readdirSync("tasks").filter(f=>f.endsWith(".json")).sort(); +assert.deepEqual(taskFiles, ["documentation-systems.json","enterprise-compliance.json","protocol-review.json","security-adversarial-review.json","surface-frontend.json","verifier-engineering.json"]); + +const schema = JSON.parse(fs.readFileSync("schemas/submission.schema.json", "utf8")); +assert.equal(schema.properties.track.enum.length, 6); +assert.equal(schema.properties.constraints.properties.unpaid_ack.const, true); + +const submitHtml = fs.readFileSync("public/submit/index.html", "utf8"); +for (const token of ['name="artifact_link"', 'name="work_links"', 'name="unpaid_ack"', 'data-endpoint="/api/submit"']) assert.ok(submitHtml.includes(token), token); + +const submitJs = fs.readFileSync("public/assets/apply-submit.js", "utf8"); +for (const token of ["missing_artifact","missing_work_links","bot_trap","output_first_ack"]) assert.ok(submitJs.includes(token), token); + +const scoring = fs.readFileSync("functions/lib/scoring.ts", "utf8"); +for (const token of ["0.5 * output_presence","0.2 * link_quality","0.2 * alignment","0.1 * clarity"]) assert.ok(scoring.includes(token), token); + +const submitFn = fs.readFileSync("functions/api/submit.ts", "utf8"); +for (const token of ["validateSubmission","scoreSubmission","checkRateLimit","makeReceipt","APPLY_WEBHOOK_URL","blocked_attempts"]) assert.ok(submitFn.includes(token), token); + +const adminFn = fs.readFileSync("functions/api/admin/submissions.ts", "utf8"); +for (const token of ["assertAdmin","review_decisions","submission_events"]) assert.ok(adminFn.includes(token), token); + +const root = fs.readFileSync("public/index.html", "utf8"); +for (const token of ["Terminal intake control plane","does not publish proof","verify truth","recognize terminal truth","assign recourse"]) assert.ok(root.includes(token), token); + +const status = fs.readFileSync("functions/api/status.ts", "utf8"); +assert.ok(status.includes("apply_intake_only")); +assert.ok(status.includes("INTAKE_ONLY_NOT_TRUTH")); + +const host = JSON.parse(fs.readFileSync("surface.host.json", "utf8")); +assert.equal(host.host, "[https://apply.verifrax.net](https://apply.verifrax.net)"); +assert.equal(host.role, "apply"); +assert.equal(host.deployMode, "cloudflare-pages-functions-d1"); + +console.log("APPLY_TERMINAL_CONTRACT_OK=true"); diff --git a/wrangler.toml b/wrangler.toml new file mode 100644 index 0000000..1fb0e78 --- /dev/null +++ b/wrangler.toml @@ -0,0 +1,8 @@ +name = "verifrax-apply" +compatibility_date = "2026-05-01" +pages_build_output_dir = "public" + +[[d1_databases]] +binding = "APPLY_DB" +database_name = "verifrax-apply" +database_id = "REPLACE_WITH_D1_DATABASE_ID" From f762b97d37876873f7efaa1469e48d293d9c6c61 Mon Sep 17 00:00:00 2001 From: Midia Kiasat Date: Tue, 19 May 2026 23:22:56 +0200 Subject: [PATCH 2/3] Align APPLY surface identity contract --- surface.host.json | 15 +++++++++++++-- tests/apply-terminal-contract.test.mjs | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/surface.host.json b/surface.host.json index 67861e2..ea4397c 100644 --- a/surface.host.json +++ b/surface.host.json @@ -1,9 +1,20 @@ { - "host": "[https://apply.verifrax.net](https://apply.verifrax.net)", + "host": "https://apply.verifrax.net", "repo": "apply", "hostClass": "tool", "role": "apply", "title": "VERIFRAX Apply", "description": "Terminal intake control plane for VERIFRAX. This host converts untrusted human intent into structured private review signal only. It does not publish proof, verify truth, issue authority, execute governed actions, recognize terminal truth, or assign recourse.", - "deployMode": "cloudflare-pages-functions-d1" + "deployMode": "static-root", + "adjacentHosts": { + "Root": "https://www.verifrax.net", + "Docs": "https://docs.verifrax.net", + "Proof": "https://proof.verifrax.net", + "Verify": "https://verify.verifrax.net", + "Authority": "https://auctoriseal.verifrax.net", + "Runtime": "https://corpiform.verifrax.net", + "Execution": "https://api.verifrax.net", + "Status": "https://status.verifrax.net", + "Archive": "https://sigillarium.verifrax.net" + } } diff --git a/tests/apply-terminal-contract.test.mjs b/tests/apply-terminal-contract.test.mjs index 0d394f6..115d6a9 100644 --- a/tests/apply-terminal-contract.test.mjs +++ b/tests/apply-terminal-contract.test.mjs @@ -41,8 +41,8 @@ assert.ok(status.includes("apply_intake_only")); assert.ok(status.includes("INTAKE_ONLY_NOT_TRUTH")); const host = JSON.parse(fs.readFileSync("surface.host.json", "utf8")); -assert.equal(host.host, "[https://apply.verifrax.net](https://apply.verifrax.net)"); +assert.equal(host.host, "https://apply.verifrax.net"); assert.equal(host.role, "apply"); -assert.equal(host.deployMode, "cloudflare-pages-functions-d1"); +assert.ok(["static-root", "cloudflare-pages-functions-d1"].includes(host.deployMode)); console.log("APPLY_TERMINAL_CONTRACT_OK=true"); From 9299a7adaad46e7e05038111835ce551e5d16ccb Mon Sep 17 00:00:00 2001 From: Midia Kiasat Date: Wed, 20 May 2026 19:37:49 +0200 Subject: [PATCH 3/3] Reproject APPLY surface output --- 404.html | 5 ++-- index.html | 85 +++++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 78 insertions(+), 12 deletions(-) diff --git a/404.html b/404.html index 1ccc1cd..49e125b 100644 --- a/404.html +++ b/404.html @@ -4,7 +4,7 @@ VERIFRAX Apply - + @@ -12,7 +12,7 @@
VERIFRAX / apply

404 — VERIFRAX Apply

-

Intake surface for the VERIFRAX public perimeter. This surface accepts intake only. It does not publish proof, determine verification truth, issue authority, or execute governed actions.

+

Terminal intake control plane for VERIFRAX. This host converts untrusted human intent into structured private review signal only. It does not publish proof, verify truth, issue authority, execute governed actions, recognize terminal truth, or assign recourse.

Bounded public tool surface inside the VERIFRAX perimeter.

@@ -28,6 +28,7 @@

System map

  • Runtimecorpiform.verifrax.net
  • Executionapi.verifrax.net
  • Statusstatus.verifrax.net
  • +
  • Archivesigillarium.verifrax.net
  • diff --git a/index.html b/index.html index 721a1fd..b32d768 100644 --- a/index.html +++ b/index.html @@ -1,11 +1,76 @@ -VERIFRAX Apply -
    - -
    VERIFRAX / apply
    -

    Output before talk.

    -

    Terminal intake control plane.

    -

    This host converts untrusted human intent into structured private review signal only. It does not publish proof, verify truth, issue authority, execute governed actions, recognize terminal truth, or assign recourse.

    -

    Do not apply if

    • you want talk before output
    • you cannot produce one artifact
    • you want narrative to replace evidence
    -

    Path

    1. Choose one lane.
    2. Complete one bounded task.
    3. Submit one artifact.
    4. Enter private queue.
    -
    + + + + + VERIFRAX Apply + + + + + +
    +
    VERIFRAX / apply
    +

    VERIFRAX Apply

    +

    Terminal intake control plane for VERIFRAX. This host converts untrusted human intent into structured private review signal only. It does not publish proof, verify truth, issue authority, execute governed actions, recognize terminal truth, or assign recourse.

    +

    Bounded public tool surface inside the VERIFRAX perimeter.

    +
    + +
    + + +
    +

    Host contract

    +

    Static public host.

    +
      +
    • One host. One active function.
    • +
    • Tool surfaces may expose operator or machine-adjacent affordances without claiming adjacent-host authority.
    • +
    • Execution, verification, intake, and status are not interchangeable.
    • +
    +
    +
    + +
    +

    Surface authority

    +
      +
    • Hosthttps://apply.verifrax.net
    • +
    • Repositoryapply
    • +
    • Host classtool
    • +
    • Surface roleapply
    • +
    • Projection sourceVERIFRAX-SURFACE@c8797ad02030
    • +
    +

    Form comes from the surface authority. Host purpose and content stay owned by the host repository.

    +
    + +
    +

    Reading order

    + +
    + + +
    + +