diff --git a/.env.example b/.env.example index 03eacf3..9ab5630 100644 --- a/.env.example +++ b/.env.example @@ -10,6 +10,8 @@ CANTON_MAINTAINER_TOKEN= CANTON_CONTRIBUTOR_TOKEN= CANTON_VERIFIER_TOKEN= CANTON_USER_ID= +# Label copied into proof artifacts. Use authenticated-devnet only after connecting to real DevNet. +CANTON_ENVIRONMENT_LABEL= # Explicit local sandbox only. Never enable for a remote/production service. CANTON_INSECURE_LOCAL=false COMMITLEDGER_ISSUE_URL=https://github.com/Saidur-droid/CommitLedger/issues/5 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5127877..aa86302 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,7 +1,7 @@ name: Verified Delivery on: push: - branches: [main, 'fix/**'] + branches: [main, 'fix/**', 'season4/**'] pull_request: workflow_dispatch: permissions: @@ -71,6 +71,10 @@ jobs: test -f docs/EVIDENCE_MANIFEST.md test -f docs/DEMO_SCRIPT.md test -f docs/SUBMISSION_DRAFT.md + test -f docs/SEASON4_RULES_SNAPSHOT.md + test -f docs/SEASON4_LOCKED_PLAN.md + test -f docs/DEVNET_PROOF_RUNBOOK.md + test -f docs/VALIDATION_SPRINT.md test -f daml/daml/CommitLedger.daml ! grep -RniE 'vercel|supabase' package.json src web scripts daml ! git ls-files | grep -E '(^|/)\.env(\.local)?$' diff --git a/README.md b/README.md index afb66c7..4c40de2 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,76 @@ # CommitLedger -**Canton-native settlement infrastructure for verified open-source work.** +**Verified work. Authorized settlement. Replay-safe receipt.** -CommitLedger binds canonical contribution evidence to role-separated authorization and an auditable settlement receipt. +CommitLedger is a Canton-native business workflow that turns canonical GitHub contribution evidence into a role-authorized settlement state and an auditable `SettlementReceipt`. -## Active competition targets — 7 October 2026 +## HackCanton Season 4 target -This sprint has exactly two active submission targets: +**Primary track:** Real-World Asset (RWA) & Business Workflows -1. **HackCanton Season 3** - - Submission deadline: **9 Oct 2026, 23:59 UTC** - - Bangladesh time: **10 Oct 2026, 05:59** -2. **Crypto World's Fair — Colosseum** - - Contest/submission cutoff: **12 Oct 2026, 23:59 PT** - - Bangladesh time: **13 Oct 2026, 12:59** +Business story: -The 1 October plan that retired HackCanton is superseded by the owner's 7 October instruction to submit CommitLedger to both programs. +> A foundation pays contributors only after independently verified work, with no duplicate settlement and a permanent audit receipt. -See [Competition Targets](docs/COMPETITION_TARGETS.md), [Submission Status](docs/SUBMISSION_STATUS_20261007.md), [Final Checklist](docs/FINAL_CHECKLIST.md), and [Submission Draft](docs/SUBMISSION_DRAFT.md). +Core flow: -## Product thesis +`GitHub Issue -> Bounty -> Claim -> Pull Request -> Verify -> Settle -> SettlementReceipt` -`GitHub Issue -> Bounty -> Claim -> Pull Request -> Merge Evidence -> Canton Settlement -> SettlementReceipt` +### Why Canton is essential -Canton/Daml is the authorization and workflow-state layer, not a cosmetic integration. GitHub remains the canonical external work-evidence source. +GitHub proves the work event. Canton/Daml controls what each party is allowed to do next. -## Core guarantees +- Maintainer creates, accepts and settles. +- Contributor claims work and submits the PR. +- Verifier attests canonical merge evidence. +- Wrong evidence is rejected. +- Unauthorized settlement is rejected. +- Duplicate settlement is rejected because the verified contract is consumed. +- Settlement creates an inspectable receipt. -- **Maintainer** creates the bounty, accepts the claim and settles verified work. -- **Contributor** claims work and submits the exact PR. -- **Verifier** attests canonical merge evidence. -- Merge evidence is bound to the exact issue and PR metadata. -- Wrong evidence, unauthorized actions and replay/duplicate settlement are rejected. -- Settlement consumes the verified contract and creates an auditable `SettlementReceipt`. -- `DEMO_CREDIT` is explicitly non-production test value. +## Season 4 judge experience -## Frozen technical proof +The Season 4 branch adds only judge-facing upgrades around the proven core: -The last fully executed, source-bound technical proof is: +- **60-second Judge Mode** +- **Evidence Passport** +- **same-run replay/duplicate rejection spotlight** +- **business-first workflow framing** +- **authenticated DevNet-ready proof path** +- **real validation sprint kit** + +The Daml authorization model, GitHub verifier, six-step lifecycle and settlement semantics are intentionally not rewritten. + +## Proven technical baseline + +Last fully executed frozen proof before Season 4 polish: `26bd992787401f6458f6685d2ab76aacd05eab4e` -Verified at that exact code commit: +Verified there: -- Node tests: **86/86 PASS** -- DPM **3.5.12** PASS +- Node tests: 86/86 PASS +- DPM 3.5.12 PASS - Daml build PASS - Daml Script tests PASS - fresh Canton sandbox PASS - six ledger transitions PASS -- `SettlementReceipt` generated +- SettlementReceipt generated - wrong-evidence rejection captured - unauthorized-settlement rejection captured - duplicate/replay rejection captured -External GitHub evidence fixture: +Current Season 4 branch must pass the same proof pipeline before being called technically complete. + +## Real evidence fixture - Repository: `Saidur-droid/MergeEarn` - Open issue: `#69` - Merged PR: `#73` -**MergeEarn is only the external proof fixture. CommitLedger is the product being submitted.** +MergeEarn is only the external GitHub evidence fixture. CommitLedger is the product. -Canonical proof service: +## Public proof service https://commitledger-proof-final.onrender.com @@ -70,48 +78,20 @@ Proof JSON: https://commitledger-proof-final.onrender.com/api/proof -Planning/documentation commits after the frozen proof do not become runtime-proven automatically. If executable code changes, rerun the complete proof on the exact new commit. - -## Run locally - -Requires Node.js 22+. - -```bash -npm test -npm start -``` - -Open `http://127.0.0.1:4173`. - -## Run the full Canton proof - -Configure the documented Canton environment values, then run: - -```bash -bash scripts/run-local-proof.sh -``` - -The proof path reruns tests, builds/tests Daml, starts a fresh Canton sandbox, captures each ledger transition, executes negative authorization/replay checks, validates one coherent evidence bundle, and finishes at `SettlementReceipt`. +The existing public service reflects the previously frozen proven build until the Season 4 branch is redeployed. -## Submission assets +## Season 4 control docs -- [Rules recheck — 7 Oct](docs/RULES_RECHECK_20261007.md) -- [Submission status — 7 Oct](docs/SUBMISSION_STATUS_20261007.md) -- [Competition targets](docs/COMPETITION_TARGETS.md) +- [Rules snapshot](docs/SEASON4_RULES_SNAPSHOT.md) +- [Locked winning plan](docs/SEASON4_LOCKED_PLAN.md) +- [DevNet proof runbook](docs/DEVNET_PROOF_RUNBOOK.md) +- [Validation sprint](docs/VALIDATION_SPRINT.md) - [Final checklist](docs/FINAL_CHECKLIST.md) -- [Submission master draft](docs/SUBMISSION_DRAFT.md) -- [HackCanton pitch](docs/PITCH.md) -- [HackCanton demo script](docs/DEMO_SCRIPT.md) -- [Colosseum pitch script](docs/COLOSSEUM_PITCH_SCRIPT.md) -- [Colosseum demo script](docs/COLOSSEUM_DEMO_SCRIPT.md) -- [Hackathon work disclosure](docs/HACKATHON_WORK_DISCLOSURE.md) -- [AI assistance disclosure](docs/AI_DISCLOSURE.md) -- [Delivery status](docs/DELIVERY_STATUS.md) ## Integrity -CommitLedger does not claim Canton Coin transfer, fiat settlement, external adoption, MainNet usage, revenue, paying customers, or production custody without evidence. +Do not claim DevNet, MainNet, real-money settlement, customers, revenue, traction or production custody without executed evidence. -`DEMO_CREDIT` is test value only. +`DEMO_CREDIT` is non-production test value. -Canton is a registered trademark of Digital Asset (Switzerland) GmbH. CommitLedger is an independent project and is not sponsored or endorsed by Digital Asset. +Canton is a registered trademark of Digital Asset (Switzerland) GmbH. CommitLedger is independent and is not sponsored or endorsed by Digital Asset. diff --git a/docs/BUILD_STATUS.md b/docs/BUILD_STATUS.md index 60deda7..a4f5aca 100644 --- a/docs/BUILD_STATUS.md +++ b/docs/BUILD_STATUS.md @@ -1,7 +1,46 @@ -# Build Status +# Build Status — HackCanton Season 4 -Last reviewed: 2026-09-29. +_Last updated: 7 October 2026._ -See [Delivery status](DELIVERY_STATUS.md) for the current evidence-based status, [Automated runbook](AUTOMATED_RUNBOOK.md) for execution, and [Final checklist](FINAL_CHECKLIST.md) for release/submission gates. +## Current branch -Original Node suite: 16 passed. Expanded delivery Node suite: 65 passed. Daml build/tests, real Canton lifecycle evidence, full browser QA, final video, and official portal recheck remain unverified. CI configuration is not CI success. Do not claim 100% or submission-ready before those gates pass. +`season4/jaw-drop-upgrade` + +## Technical baseline + +The proven pre-Season-4 baseline is commit: + +`26bd992787401f6458f6685d2ab76aacd05eab4e` + +It passed: +- Node 86/86; +- DPM 3.5.12; +- Daml build/tests; +- fresh Canton sandbox; +- six real ledger transitions; +- SettlementReceipt; +- wrong-evidence rejection; +- unauthorized-settlement rejection; +- duplicate/replay rejection. + +## Season 4 delta + +Implemented: +- Judge Mode; +- Evidence Passport; +- replay rejection spotlight; +- business-first Season 4 copy; +- DevNet-ready environment labeling/runbook; +- validation sprint kit; +- Season 4 CI coverage. + +Current gate: +- the Season 4 branch must pass the full CI/proof pipeline on its exact source commit. + +External/manual gates are separate: +- Season 4 registration; +- authenticated DevNet access/run; +- real validation interviews; +- final video and portal submission. + +Do not call those external gates complete until they actually happen. diff --git a/docs/DELIVERY_STATUS.md b/docs/DELIVERY_STATUS.md index b1bfd30..6edc319 100644 --- a/docs/DELIVERY_STATUS.md +++ b/docs/DELIVERY_STATUS.md @@ -1,79 +1,50 @@ -# Delivery Status — 7 October 2026 +# Delivery Status — HackCanton Season 4 -Delivery branch: `fix/verified-delivery-20260929`. +_Last updated: 7 October 2026._ -## Product / technical status +## Product status -**Technical delivery is GREEN.** +**Core product: complete.** -Frozen fully executed proof commit: - -`26bd992787401f6458f6685d2ab76aacd05eab4e` - -Canonical Render proof service: - -`commitledger-proof-final` - -Live page: -https://commitledger-proof-final.onrender.com - -Proof endpoint: -https://commitledger-proof-final.onrender.com/api/proof - -Successful proven deploy recorded in project history: -`dep-daujs4m0tbcc73dn0c80` - -Verified on the frozen code state: -- Node 86/86 PASS; -- DPM 3.5.12 PASS; -- Daml build PASS; -- Daml Script tests PASS; -- Java 21 runtime; -- fresh Canton sandbox; -- DAR/package identity extraction; -- three distinct demo parties; -- external GitHub fixture `Saidur-droid/MergeEarn#69 -> PR #73`; -- six real Canton transitions; +CommitLedger already has: +- Canton/Daml role authorization; +- canonical GitHub issue/PR verification; +- six-step lifecycle; - SettlementReceipt; - wrong-evidence rejection; - unauthorized-settlement rejection; -- duplicate/replay rejection; -- source-commit binding. +- duplicate/replay rejection. -## Active competition direction +## Season 4 judge polish -The current sprint has exactly two active targets: +**Implemented on `season4/jaw-drop-upgrade`:** +- 60-second Judge Mode; +- Evidence Passport; +- visible duplicate-settlement rejection moment; +- RWA / Business Workflows positioning; +- DevNet-ready proof path; +- validation sprint package. -1. **HackCanton Season 3** -2. **Crypto World's Fair — Colosseum** +## Proof status -The 1 October retirement of HackCanton is superseded by the owner's 7 October instruction. +Frozen previously proven commit: +`26bd992787401f6458f6685d2ab76aacd05eab4e` -## Submission readiness +Current Season 4 branch: +**CI / exact-commit proof must be green before merge/deploy.** -### HackCanton -- technical product: DONE; -- evidence/security proof: DONE; -- written pitch/demo plan: DONE; -- rules deadline recheck: DONE; -- logged-in AppsFactory eligibility/profile state: **PENDING MANUAL CHECK**; -- recorded final video: PENDING; -- repo/publication gate: PENDING; -- final portal submission/receipt: PENDING. +## External status -### Colosseum -- technical product: DONE; -- official rules recheck: DONE; -- pre-existing-work approach: DONE; -- submission copy: DRAFTED; -- presentation/demo scripts: DONE; -- portal registration/join state: **PENDING MANUAL CHECK**; -- real demand validation: PENDING if available; -- final videos: PENDING; -- final portal submission/receipt: PENDING. +Still user/organizer dependent: +- Season 4 registration confirmation; +- logged-in portal requirements; +- authenticated DevNet credentials/environment; +- 3–5 real validation conversations; +- final demo video; +- final submission. -## Engineering state +## Release rule -Do not reopen product engineering unless a verified rule requires it or a real defect appears. +Technical product may be called **100% technically ready** only after the current Season 4 exact commit passes the full Node + Daml + real local Canton proof pipeline. -Documentation-only commits may advance the branch without changing the frozen technical proof claim. If executable code changes, rerun the full proof on the exact new commit. +Competition submission may be called **100% ready** only after the external/manual gates above are also complete. diff --git a/docs/DEVNET_PROOF_RUNBOOK.md b/docs/DEVNET_PROOF_RUNBOOK.md new file mode 100644 index 0000000..bd6457b --- /dev/null +++ b/docs/DEVNET_PROOF_RUNBOOK.md @@ -0,0 +1,55 @@ +# Season 4 DevNet Proof Runbook + +Goal: reproduce the existing six-step lifecycle on an **authenticated Canton environment** without changing the product semantics. + +## Required organizer/environment inputs + +- Canton JSON Ledger API URL +- uploaded CommitLedger package ID +- Maintainer party +- Contributor party +- Verifier party +- authenticated token(s) with the minimum rights needed for those parties +- optional Canton user ID +- GitHub read token if the evidence repository is private + +Never commit any token. + +## Configuration + +Use an ignored local environment file or shell variables: + +```bash +CANTON_JSON_API_URL=https:// +CANTON_PACKAGE_ID= +CANTON_PACKAGE_NAME=commit-ledger +CANTON_MAINTAINER_PARTY= +CANTON_CONTRIBUTOR_PARTY= +CANTON_VERIFIER_PARTY= +CANTON_MAINTAINER_TOKEN= +CANTON_CONTRIBUTOR_TOKEN= +CANTON_VERIFIER_TOKEN= +CANTON_USER_ID= +CANTON_INSECURE_LOCAL=false +CANTON_ENVIRONMENT_LABEL=authenticated-devnet +``` + +## Proof command + +Run the normal proof path against the authenticated environment. Do not bypass GitHub verification or negative checks. + +Expected evidence: +- exact source commit; +- six Canton updates/contracts; +- final SettlementReceipt; +- wrong-issue rejection; +- unauthorized settlement rejection; +- duplicate settlement rejection; +- exported proof JSON; +- exported Evidence Passport. + +## Pass condition + +Only mark DevNet **VERIFIED** after the evidence bundle contains all required transitions/rejections and is source-commit coherent. + +Until then the correct status is **DEVNET PENDING**. diff --git a/docs/FINAL_CHECKLIST.md b/docs/FINAL_CHECKLIST.md index 4b8c23e..fd63b80 100644 --- a/docs/FINAL_CHECKLIST.md +++ b/docs/FINAL_CHECKLIST.md @@ -1,99 +1,54 @@ -# CommitLedger — HackCanton + Colosseum Final Checklist +# CommitLedger — HackCanton Season 4 Final Checklist _Last updated: 7 October 2026._ -## Shared frozen technical baseline - -- [x] Product core implemented. -- [x] Canonical GitHub evidence verification implemented. -- [x] Role-separated Maintainer / Contributor / Verifier workflow implemented. -- [x] Node tests: 86/86 PASS on frozen proof commit. -- [x] DPM 3.5.12 PASS. -- [x] Daml build PASS. -- [x] Daml Script tests PASS. -- [x] Fresh Canton sandbox proof completed. -- [x] Six-step ledger lifecycle completed. -- [x] SettlementReceipt generated. -- [x] Wrong-evidence rejection captured. -- [x] Unauthorized-settlement rejection captured. -- [x] Duplicate/replay rejection captured. -- [x] Public read-only proof service recorded. -- [x] Frozen proof commit: `26bd992787401f6458f6685d2ab76aacd05eab4e`. -- [x] AI assistance disclosure exists. -- [x] Hackathon work disclosure exists. -- [x] HackCanton pitch copy exists. -- [x] HackCanton demo script exists. -- [x] Colosseum pitch script exists. -- [x] Colosseum demo script exists. - -If executable code changes, rerun the complete proof on the exact new code commit. - -## HackCanton Season 3 - -Deadline: **9 Oct 2026, 23:59 UTC = 10 Oct 2026, 05:59 Bangladesh time**. - -### Rules / eligibility -- [x] Public deadline rechecked on 7 Oct. -- [x] Solo/team format publicly supported. -- [x] Canton-native fit documented. -- [ ] Logged-in AppsFactory registration state confirmed. -- [ ] Team/project profile completeness confirmed. -- [ ] Exact portal track selected and confirmed. -- [ ] Any private portal activity/Mana/journal requirements checked. -- [ ] Eligibility status confirmed from the participant portal. - -### Submission package -- [x] Product description drafted. -- [x] Canton integration explanation drafted. -- [x] Architecture/security evidence ready. -- [x] Demo storyboard ready. -- [x] <=5-minute target demo script ready. -- [ ] Final HackCanton video recorded. -- [ ] Video reviewed for secrets, legibility and audio. -- [ ] Repository accessible to judges. -- [ ] Live proof link tested in logged-out/private browser. -- [ ] Proof JSON link tested in logged-out/private browser. -- [ ] Final portal fields completed. -- [ ] Final Submit action completed. -- [ ] Submission receipt / confirmation retained. - -**Stop condition:** if the logged-in portal shows a mandatory gate that cannot be truthfully satisfied, do not fake it. Preserve the technical package and submit only if the official portal allows an eligible entry. - -## Crypto World's Fair — Colosseum - -Official cutoff: **12 Oct 2026, 11:59 PM PT = 13 Oct 2026, 12:59 Bangladesh time**. - -### Eligibility / registration -- [x] Official rules PDF rechecked on 7 Oct. -- [x] No-purchase requirement confirmed. -- [x] Age rule captured. -- [x] Bangladesh not listed among current excluded jurisdictions. -- [x] English-content requirement captured. -- [x] Pre-existing-code disclosure rule captured from current FAQ. -- [ ] Colosseum account/login confirmed. -- [ ] Crypto World's Fair joined. -- [ ] Team status confirmed. -- [ ] Project record created in portal. - -### Submission package -- [x] Product positioning drafted. -- [x] Technical proof ready. -- [x] Honest pre-existing-work disclosure draft ready. -- [x] Founder/market story draft ready. -- [x] Business model/GTM draft ready. -- [x] Presentation script ready. -- [x] Product demo script ready. -- [ ] Real demand/user validation added if available. -- [ ] 2–3 minute presentation video recorded. -- [ ] <=3 minute demo video recorded. -- [ ] Logo/graphic selected. -- [ ] Repository accessible to judges or review access granted. -- [ ] All content checked to be English. -- [ ] Final links tested logged-out where applicable. -- [ ] Final portal review completed. -- [ ] Final Submit action completed. +## Core product +- [x] Canton/Daml authorization model. +- [x] Maintainer / Contributor / Verifier separation. +- [x] Canonical GitHub issue/PR verification. +- [x] Six-step settlement lifecycle. +- [x] SettlementReceipt. +- [x] Wrong-evidence rejection. +- [x] Unauthorized-settlement rejection. +- [x] Duplicate/replay rejection. + +## Season 4 judge polish +- [x] 60-second Judge Mode. +- [x] Evidence Passport implementation. +- [x] Rejection spotlight. +- [x] Business-first RWA workflow story. +- [x] Season 4 rules snapshot. +- [x] Locked scope plan. +- [x] DevNet proof runbook. +- [x] Validation sprint kit. +- [x] Season 4 CI branch coverage. + +## Exact-commit technical proof +- [ ] Current Season 4 Node suite PASS. +- [ ] DPM 3.5.12 PASS. +- [ ] Daml build PASS. +- [ ] Daml Script tests PASS. +- [ ] Fresh local Canton sandbox PASS. +- [ ] Six transitions captured from current commit. +- [ ] SettlementReceipt captured from current commit. +- [ ] All three rejection proofs captured from current commit. +- [ ] Evidence Passport source-bound to current proof. +- [ ] PR checks green. +- [ ] Merge/release branch finalized. +- [ ] Season 4 build deployed to judge-accessible URL. + +## External/manual competition gates +- [ ] Season 4 registration confirmed. +- [ ] Logged-in portal requirements checked. +- [ ] Track selection confirmed in portal. +- [ ] Authenticated DevNet environment obtained. +- [ ] Authenticated DevNet proof captured, or clearly marked pending/not required. +- [ ] 3–5 real validation conversations completed. +- [ ] Final demo video recorded and QA'd. +- [ ] Judge repository access confirmed. +- [ ] Final submission completed. - [ ] Submission receipt retained. -## Release rule +## Integrity rule -Do not claim either competition is submitted until the portal itself returns a confirmation/receipt. +Do not convert an external/manual pending item into a technical claim. No fake DevNet, traction, customer, revenue, MainNet or real-money claims. diff --git a/docs/SEASON4_LOCKED_PLAN.md b/docs/SEASON4_LOCKED_PLAN.md new file mode 100644 index 0000000..75b0f9a --- /dev/null +++ b/docs/SEASON4_LOCKED_PLAN.md @@ -0,0 +1,86 @@ +# CommitLedger — HackCanton Season 4 Locked Winning Plan + +**Status: APPROVED / LOCKED — 7 October 2026** + +## Goal + +Turn the already strong Canton-native CommitLedger core into a finalist-quality, judge-first product without rewriting the architecture. + +## Scope lock + +**Keep approximately 85–90% of the proven core unchanged.** + +Do not rewrite: +- Daml authorization model; +- canonical GitHub verifier; +- six-step lifecycle; +- SettlementReceipt semantics; +- replay/duplicate protection; +- wrong-evidence rejection; +- unauthorized-settlement rejection. + +Season 4 work is intentionally concentrated in the judge-visible 10–15%. + +## Six locked upgrades + +### 1. Judge Mode +One screen tells the complete story: +**real work → independent evidence → authorized settlement → receipt**. + +A judge should understand the product before opening a terminal. + +### 2. Rejection Moment +After a successful settlement, surface the same-run duplicate settlement rejection as the dramatic proof that consumed-contract semantics matter. + +Never fake a rejection. A network failure is not authorization proof. + +### 3. Authenticated DevNet Proof +Keep the reproducible local proof, then capture a new authenticated DevNet proof if organizer credentials/environment are available. + +Do not label a run DevNet unless it was actually executed there. + +### 4. Business-First Story +Primary sentence: + +> A foundation pays contributors only after independently verified work, with no duplicate settlement and an auditable receipt. + +Technical details support the story; they do not lead it. + +### 5. Evidence Passport +Create a compact machine-readable and judge-readable proof summary tying: +**GitHub work → roles → Canton receipt → attack rejections → source commit**. + +### 6. Real Validation +Collect 3–5 real conversations with maintainers, foundations, ecosystem operators, or developer-program owners. + +No invented quotes, users, pilots, or demand. + +## Winning demo story + +> A contribution merged. That is evidence, not permission to pay. +> +> CommitLedger verifies the exact work, separates Maintainer / Contributor / Verifier authority, settles only after the proof is valid, creates a Canton receipt, and then rejects the same settlement when we try it again. +> +> GitHub proves what happened. Canton controls what is allowed to happen next. + +## Definition of done + +- Judge Mode works without terminal dependency. +- Evidence Passport endpoint/card is inspectable. +- Fresh lifecycle can run when a real ledger is connected. +- Duplicate settlement rejection is visible from the same proof run. +- Season 4 business brief + pilot plan map directly to the RWA/Business Workflow expected outputs. +- DevNet proof is either VERIFIED with evidence or explicitly PENDING. +- At least 3 real validation responses are recorded, or validation remains honestly pending. +- Demo and submission contain no unsupported claim. + +## Feature rule + +No new feature is allowed unless it improves: +1. rule compliance; +2. judge comprehension; +3. proof strength; +4. business credibility; +5. demo reliability. + +Everything else is scope creep. diff --git a/docs/SEASON4_RULES_SNAPSHOT.md b/docs/SEASON4_RULES_SNAPSHOT.md new file mode 100644 index 0000000..7a228c1 --- /dev/null +++ b/docs/SEASON4_RULES_SNAPSHOT.md @@ -0,0 +1,68 @@ +# HackCanton Season 4 — Verified Public Rules Snapshot + +_Last verified: 7 October 2026 from the current AppsFactory Hackathons page._ + +This file records only public facts that can be verified now. Logged-in portal instructions and later organizer updates override this snapshot. + +## Public schedule + +- Registration & Team Formation: **24 Sep → 12 Nov 2026** +- Opening ceremony: **12 Nov 2026, 12:00 UTC** +- Delivery/build phase: **13 Nov → 6 Dec 2026** +- Submission deadline: **6 Dec 2026, 23:59 UTC** +- Closing ceremony: **7 Dec 2026, 12:00 UTC** +- Async judging: **7–13 Dec 2026** +- Finalists announced: **14 Dec 2026** +- Grand Final: **16 Dec 2026, 14:00 UTC** +- Finalist field: **Top 5–10** +- Prize pool: **up to $50,000 in cash & credits** + +## Public participation rules + +- Everyone can participate. +- Solo participation is allowed; teams are also allowed. +- Participation is free. +- Existing code may be used if it complies with the competition rules. +- A project can enter up to two tracks. +- The project must be built on the Canton Network. +- Public materials advertise DevNet environment/support. +- AI integration is encouraged where it adds real value; it is not treated here as mandatory. + +## Track selected for CommitLedger + +**Primary: Real-World Asset (RWA) & Business Workflows** + +Public expected output: +1. MVP with at least one end-to-end workflow: create → update status → transfer/fulfill → audit/report. +2. Lightweight role-based UI. +3. One-page business brief covering ICP, use case, who pays, and why Canton. +4. Short pilot plan with 2–3 steps and required integrations. + +CommitLedger maps directly: +- create → Bounty; +- update → Claim + Pull Request; +- fulfill → verified settlement; +- audit/report → SettlementReceipt + Evidence Passport. + +## Track strategy + +Use one primary track unless a second track adds a clear prize advantage without diluting the story. Do not enter Open Track merely for extra surface area; the public page notes that it has a smaller prize pool than core ecosystem tracks. + +## MainNet / DevNet integrity + +The public FAQ wording we could verify establishes that the project must be built on Canton, but does not establish a separate requirement that the final proof must be on MainNet. Therefore: +- do not claim MainNet unless actually used; +- target authenticated Canton DevNet proof if organizer access is available; +- preserve the existing reproducible local Canton proof as a fallback/engineering artifact; +- live portal or organizer instructions override this interpretation. + +## Submission integrity + +- Do not claim DevNet until a successful authenticated DevNet run is captured. +- Do not claim customers, revenue, production transfers, or adoption without evidence. +- DEMO_CREDIT remains non-production test value. +- Existing code is disclosed; Season 4 work must be clearly separated in Git history and submission copy. + +## Official public source + +https://appsfactory.cc/hackathons diff --git a/docs/VALIDATION_SPRINT.md b/docs/VALIDATION_SPRINT.md new file mode 100644 index 0000000..5320aba --- /dev/null +++ b/docs/VALIDATION_SPRINT.md @@ -0,0 +1,46 @@ +# Season 4 Validation Sprint + +Goal: collect a small amount of real problem validation without delaying the build. + +## Target respondents + +Prioritize 3–5 people who actually operate one of: +- open-source repositories; +- contributor/bounty programs; +- foundation grants; +- ecosystem developer programs; +- external engineering contributor workflows. + +## Three questions + +1. Where does the process between “PR merged” and “contributor paid/settled” break or become manual today? +2. Would independent evidence + role-separated approval + a replay-safe receipt solve a real problem for your program? Why or why not? +3. What would you need to see before piloting this on one repository? + +Optional: +- Who owns the budget? +- What tool/process do you use now? +- What would make this a “must have” rather than “nice to have”? + +## Evidence rules + +Record: +- date; +- respondent role/company/community only if they consent; +- exact or faithful short summary; +- strongest objection; +- pilot condition. + +Do not manufacture testimonials. Do not convert polite interest into a customer claim. + +## Submission use + +Good: +> “Three maintainers we spoke with consistently described manual approval/audit handoffs after merge.” + +Only say this after three real conversations actually support it. + +Bad: +> “Teams love CommitLedger.” + +Never use unsupported generalizations. diff --git a/src/evidence-passport.mjs b/src/evidence-passport.mjs new file mode 100644 index 0000000..f06868f --- /dev/null +++ b/src/evidence-passport.mjs @@ -0,0 +1,56 @@ +function required(value, name) { + if (value === undefined || value === null || value === "") throw new Error(`${name} is required`); + return value; +} + +export function buildEvidencePassport(proof) { + if (!proof || typeof proof !== "object") throw new Error("proof is required"); + if (!Array.isArray(proof.steps) || proof.steps.length !== 6) throw new Error("complete six-step proof is required"); + if (!Array.isArray(proof.negativeChecks) || proof.negativeChecks.length !== 3) throw new Error("three negative checks are required"); + const receipt = required(proof.settlementReceipt, "settlementReceipt"); + const settled = proof.steps.find(step => step.name === "SETTLED") || proof.steps.at(-1); + required(settled?.contractId, "settlement receipt contractId"); + required(settled?.updateId, "settlement updateId"); + + return { + schemaVersion: 1, + product: "CommitLedger", + runId: required(proof.runId, "runId"), + generatedAt: required(proof.generatedAt, "generatedAt"), + sourceCommit: required(proof.sourceCommit, "sourceCommit"), + environment: required(proof.environment, "environment"), + workEvidence: { + repository: required(receipt.repository, "receipt.repository"), + issueNumber: required(receipt.issueNumber, "receipt.issueNumber"), + pullRequestNumber: required(receipt.pullRequest?.prNumber, "receipt.pullRequest.prNumber"), + mergeCommitSha: required(receipt.mergeCommitSha, "receipt.mergeCommitSha"), + evidenceHash: required(receipt.evidenceHash, "receipt.evidenceHash") + }, + authorization: { + maintainer: required(proof.parties?.maintainer, "parties.maintainer"), + contributor: required(proof.parties?.contributor, "parties.contributor"), + verifier: required(proof.parties?.verifier, "parties.verifier"), + model: "Maintainer / Contributor / Verifier" + }, + settlement: { + rewardAmount: receipt.rewardAmount, + rewardUnit: receipt.rewardUnit, + settlementRef: receipt.settlementRef || "", + receiptContractId: settled.contractId, + updateId: settled.updateId, + completionOffset: settled.completionOffset, + packageId: required(proof.packageId, "packageId") + }, + security: { + checks: proof.negativeChecks.map(check => ({ + name: required(check.name, "negative check name"), + code: required(check.code, "negative check code") + })) + }, + integrity: { + sourceBound: true, + realMoney: false, + statement: "DEMO_CREDIT is non-production test value. This passport summarizes executed evidence; it is not a payment receipt." + } + }; +} diff --git a/src/orchestrator.mjs b/src/orchestrator.mjs index 3b0016f..f88fb9c 100644 --- a/src/orchestrator.mjs +++ b/src/orchestrator.mjs @@ -90,6 +90,7 @@ export function runtimeConfigFromEnv(env = process.env) { return { insecureLocal, userId: env.CANTON_USER_ID || "", + environmentLabel: String(env.CANTON_ENVIRONMENT_LABEL || (insecureLocal ? "local-sandbox-no-auth" : "authenticated-ledger")), baseUrl, packageId: required(env.CANTON_PACKAGE_ID, "CANTON_PACKAGE_ID"), packageName: required(env.CANTON_PACKAGE_NAME || "commit-ledger", "CANTON_PACKAGE_NAME"), @@ -151,7 +152,7 @@ export async function runFullLifecycle({ packageId, packageName, generatedAt: now().toISOString(), - environment: runtime.insecureLocal ? "local-sandbox-no-auth" : "authenticated-ledger", + environment: runtime.environmentLabel || (runtime.insecureLocal ? "local-sandbox-no-auth" : "authenticated-ledger"), issue, bounty, parties, diff --git a/src/server.mjs b/src/server.mjs index dd97f38..c629578 100644 --- a/src/server.mjs +++ b/src/server.mjs @@ -7,6 +7,7 @@ import {validateBountyDraft} from './domain.mjs'; import * as builders from './canton-commands.mjs'; import {CantonJsonApi} from './canton-json-api.mjs'; import {runtimeConfigFromEnv,runFullLifecycle} from './orchestrator.mjs'; +import {buildEvidencePassport} from './evidence-passport.mjs'; const projectRoot=fileURLToPath(new URL('../',import.meta.url)); const root=resolve(projectRoot,'web'); const evidenceRoot=resolve(projectRoot,'evidence'); @@ -59,6 +60,14 @@ export function createAppServer(env=process.env) { return json(res,503,{error:'Verified deployment proof is not available'}); } } + if(req.method==='GET' && url.pathname==='/api/passport') { + try { + const {proof}=await readVerifiedProof(); + return json(res,200,{ok:true,passport:buildEvidencePassport(proof)}); + } catch { + return json(res,503,{error:'Verified Evidence Passport is not available'}); + } + } if(req.method==='GET' && url.pathname==='/api/health') { let runtime;let configurationError='';let ledgerReachable=false; try {runtime=runtimeConfigFromEnv(env);} catch(error) {configurationError=error.message;} diff --git a/tests/evidence-passport.test.mjs b/tests/evidence-passport.test.mjs new file mode 100644 index 0000000..b63bdab --- /dev/null +++ b/tests/evidence-passport.test.mjs @@ -0,0 +1,48 @@ +import test from "node:test"; +import assert from "node:assert/strict"; +import { buildEvidencePassport } from "../src/evidence-passport.mjs"; + +const proof = { + runId: "run-1", + generatedAt: "2026-10-07T00:00:00.000Z", + sourceCommit: "a".repeat(40), + environment: "authenticated-devnet", + packageId: "b".repeat(64), + parties: { maintainer: "Maintainer::1", contributor: "Contributor::1", verifier: "Verifier::1" }, + steps: [ + {name:"BOUNTY_ON_LEDGER",contractId:"c1",updateId:"u1",completionOffset:1}, + {name:"CLAIM_REQUESTED",contractId:"c2",updateId:"u2",completionOffset:2}, + {name:"CLAIMED",contractId:"c3",updateId:"u3",completionOffset:3}, + {name:"PR_SUBMITTED",contractId:"c4",updateId:"u4",completionOffset:4}, + {name:"VERIFIED",contractId:"c5",updateId:"u5",completionOffset:5}, + {name:"SETTLED",contractId:"receipt-cid",updateId:"settle-update",completionOffset:6} + ], + negativeChecks: [ + {name:"wrong issue evidence rejected",code:"DAML_UNHANDLED_EXCEPTION"}, + {name:"unauthorized contributor settlement rejected",code:"DAML_AUTHORIZATION_ERROR"}, + {name:"duplicate settlement rejected",code:"CONTRACT_NOT_FOUND"} + ], + settlementReceipt: { + repository:"Saidur-droid/MergeEarn", + issueNumber:69, + pullRequest:{prNumber:73}, + mergeCommitSha:"c".repeat(40), + evidenceHash:"sha256:proof", + rewardAmount:"100", + rewardUnit:"DEMO_CREDIT", + settlementRef:"github:Saidur-droid/MergeEarn#73:proof" + } +}; + +test("evidence passport keeps work, authority, settlement and rejection proof together", () => { + const passport = buildEvidencePassport(proof); + assert.equal(passport.product, "CommitLedger"); + assert.equal(passport.workEvidence.issueNumber, 69); + assert.equal(passport.settlement.receiptContractId, "receipt-cid"); + assert.equal(passport.security.checks.length, 3); + assert.equal(passport.integrity.realMoney, false); +}); + +test("evidence passport fails closed for incomplete proof", () => { + assert.throws(() => buildEvidencePassport({...proof, negativeChecks: []}), /three negative checks/); +}); diff --git a/tests/judge-ui-static.test.mjs b/tests/judge-ui-static.test.mjs index f4a5c2f..613c53e 100644 --- a/tests/judge-ui-static.test.mjs +++ b/tests/judge-ui-static.test.mjs @@ -10,14 +10,14 @@ test('judge UI exposes competition readiness without claiming submission ready', assert.doesNotMatch(html, /SUBMISSION READY/); }); -test('judge UI maps all six official judging criteria', () => { - for (const label of ['Value \/ Problem','ICP \/ Audience','Metrics \/ Validation','GTM Materials','MVP Materials','Pitch Materials']) { +test('judge UI maps the Season 4 business-first case', () => { + for (const label of ['Problem','ICP','Validation','Who pays','Why Canton','Pilot path']) { assert.match(html, new RegExp(label)); } }); -test('judge UI identifies Track 1 and describes proof as evidence-first', () => { - assert.match(html, /Track 1/); +test('judge UI identifies the Season 4 RWA / Business Workflows track and remains evidence-first', () => { + assert.match(html, /RWA \/ Business Workflows/); assert.match(html, /no sample transaction IDs or simulated settlement success/i); }); @@ -29,3 +29,10 @@ test('judge cockpit exposes current verified fixture and runtime proof state', ( assert.match(html, /Runtime[\s\S]*VERIFIED/); assert.match(html, /PASS[\s\S]*Daml \+ real Canton proof/); }); + +test('Season 4 judge mode exposes passport and replay rejection story', () => { + assert.match(html, /60-SECOND JUDGE MODE/); + assert.match(html, /Open Evidence Passport/); + assert.match(html, /Show the rejection moment/); + assert.match(html, /RWA \/ Business Workflows/); +}); diff --git a/tests/orchestrator.test.mjs b/tests/orchestrator.test.mjs index a833afb..eb212b5 100644 --- a/tests/orchestrator.test.mjs +++ b/tests/orchestrator.test.mjs @@ -27,3 +27,16 @@ test("runtime config supports one local token or role-specific tokens", () => { assert.equal(config.tokens.contributor, "local-admin-token"); assert.equal(config.tokens.verifier, "local-admin-token"); }); + +test("runtime config carries explicit proof environment label", () => { + const config = runtimeConfigFromEnv({ + CANTON_JSON_API_URL: "https://devnet.example", + CANTON_PACKAGE_ID: "pkg", + CANTON_TOKEN: "token", + CANTON_MAINTAINER_PARTY: "Maintainer::1", + CANTON_CONTRIBUTOR_PARTY: "Contributor::1", + CANTON_VERIFIER_PARTY: "Verifier::1", + CANTON_ENVIRONMENT_LABEL: "authenticated-devnet" + }); + assert.equal(config.environmentLabel, "authenticated-devnet"); +}); diff --git a/tests/server.test.mjs b/tests/server.test.mjs index 3b0cafb..55b1227 100644 --- a/tests/server.test.mjs +++ b/tests/server.test.mjs @@ -58,3 +58,8 @@ test('configured public host accepts Render-style forwarded HTTPS origin',async }); assert.equal(result,503); }); + +test('verified passport endpoint fails closed when build artifacts are absent',async t=>{ + const base=await withServer(t);const response=await fetch(base+'/api/passport'); + assert.equal(response.status,503); +}); diff --git a/web/app.js b/web/app.js index 609f78e..ef49758 100644 --- a/web/app.js +++ b/web/app.js @@ -18,6 +18,22 @@ function render(proof) { const a=document.createElement('a');a.href=url;a.download=`commitledger-proof-${lastProof.runId}.json`;a.click();setTimeout(()=>URL.revokeObjectURL(url),1000); }); } +function renderPassport(passport) { + const card=$('#passport-card'); + card.classList.remove('hidden'); + card.innerHTML=`

EVIDENCE PASSPORT

${escape(passport.workEvidence.repository)} #${escape(passport.workEvidence.issueNumber)} → PR #${escape(passport.workEvidence.pullRequestNumber)}

Authority${escape(passport.authorization.model)}
Receipt contract${escape(passport.settlement.receiptContractId)}
Merge SHA${escape(passport.workEvidence.mergeCommitSha)}
Evidence hash${escape(passport.workEvidence.evidenceHash)}
Source commit${escape(passport.sourceCommit)}
Environment${escape(passport.environment)}

${escape(passport.integrity.statement)}

`; +} +function renderRejectionSpotlight(proof) { + const target=$('#rejection-spotlight'); + const duplicate=proof?.negativeChecks?.find(check=>/duplicate/i.test(check.name)) || proof?.negativeChecks?.at(-1); + if(!duplicate) return; + target.classList.remove('hidden'); + target.innerHTML=`

THE REJECTION MOMENT

Try to settle the same verified work twice.

REJECTED · ${escape(duplicate.code)}

${escape(duplicate.name)}

This is captured from the same source-bound proof run. A network error never counts as security proof.`; +} +async function loadPassport() { + const {passport}=await request('/api/passport'); + renderPassport(passport); +} async function loadProof() { try { const {proof,verification}=await request('/api/proof'); @@ -67,3 +83,7 @@ $('#verify-form').addEventListener('submit',async event=>{ }); await health(); await loadProof(); +$('#show-passport').addEventListener('click',async()=>{ + try { await loadPassport(); } catch(error) { $('#passport-card').classList.remove('hidden'); $('#passport-card').textContent=error.message; } +}); +$('#show-rejections').addEventListener('click',()=>{ if(lastProof) renderRejectionSpotlight(lastProof); }); diff --git a/web/index.html b/web/index.html index 8cc36ec..4391e7f 100644 --- a/web/index.html +++ b/web/index.html @@ -6,9 +6,9 @@ CommitLedger - Verified work, settled on Canton - +
-

GITHUB EVIDENCE / DAML AUTHORIZATION / CANTON SETTLEMENT

Work is not settled until the proof is verifiable.

From merged code to inspectable settlement: canonical GitHub evidence, explicit multi-party authorization, and a Canton receipt in one judgeable workflow.

Issue→Bounty→Claim→Pull request→Verify→Settle→Receipt
+

HACKCANTON SEASON 4 / RWA & BUSINESS WORKFLOWS

A merged PR is evidence. It is not permission to pay.

CommitLedger lets a foundation settle contributor work only after independent verification, with explicit Maintainer / Contributor / Verifier authority, a Canton receipt, and replay-safe settlement.

Issue→Bounty→Claim→Pull request→Verify→Settle→Receipt
SourceGitHub #69 → PR #73Open issue + canonical merged pull request
@@ -17,10 +17,12 @@
RuntimeVERIFIEDReal Canton proof captured during deploy
+

60-SECOND JUDGE MODE

One contribution. One authorized settlement. One receipt.

Evidence first
1Real workCanonical GitHub issue + merged PR
2Independent verificationVerifier binds exact issue, PR and merge SHA
3Authorized settlementOnly the Maintainer may settle verified work
4Replay rejectedThe consumed verified contract cannot settle twice
+
-

COMPETITION READINESS

Technical proof is green; external gates remain fail-closed

BLOCKED · external gates pending
-

The runtime proof is verified independently. Repository publication, final video, Mana/activity, journal and project-profile requirements remain blocked until they are actually verified.

-
PASSNode verification
PASSDaml + real Canton proof
BLOCKEDMana / activity / journal
BLOCKEDFinal public submission materials
+

COMPETITION READINESS

Proven core is green; Season 4 external gates remain fail-closed

BLOCKED · external gates pending
+

The proven local runtime remains independently verifiable. Season 4 registration, authenticated DevNet evidence, real validation and final media remain fail-closed until they are actually completed.

+
PASSNode verification
PASSDaml + real Canton proof
BLOCKEDRegistration / portal gates
BLOCKEDDevNet / validation / final media
@@ -34,6 +36,6 @@

CANONICAL ISSUE

Verify the work source

Waiting
Issue identity and state are fetched server-side from GitHub.

CANONICAL MERGE

Verify the merged pull request

Waiting
No merge evidence loaded.
-

OFFICIAL JUDGING CRITERIA

Six questions, six visible answers

Value / ProblemGitHub proves code events; Canton enforces who may verify and settle.
ICP / AudienceOpen-source maintainers, foundations and contributor bounty programs.
Metrics / ValidationReal GitHub fixture, deterministic tests and a source-bound Canton proof.
GTM MaterialsSingle-repo pilot → foundation/ecosystem bounty program → settlement adapter.
MVP MaterialsGitHub verification + Daml authorization + Canton receipt + attack rejection.
Pitch MaterialsProblem → proof → rejected attacks → receipt → why Canton → pilot path.
+

SEASON 4 BUSINESS-FIRST CASE

Why this is a pilot-ready Canton business workflow

ProblemGitHub proves code events; Canton enforces who may verify and settle.
ICPFoundations, ecosystem programs and teams paying external contributors.
ValidationReal GitHub fixture, deterministic tests and a source-bound Canton proof.
Who paysSingle-repo pilot → ecosystem bounty program → approved production settlement adapter.
Why CantonDaml authorization + Canton receipt + consumed-contract replay protection.
Pilot pathOne repo → one bounty program → measurable operator savings and auditability.
CommitLedger is independent. DEMO_CREDIT is non-production test value. No mainnet, real-money or traction claim is made.
diff --git a/web/styles.css b/web/styles.css index d14ae22..7a2af64 100644 --- a/web/styles.css +++ b/web/styles.css @@ -1,3 +1,14 @@ :root{font-family:Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;color:#eef4f5;background:#061014;line-height:1.5}*{box-sizing:border-box}body{margin:0;background:radial-gradient(circle at 18% -8%,#153b43 0,transparent 32%),linear-gradient(#071216,#061014)}.nav{min-height:76px;display:flex;align-items:center;justify-content:space-between;max-width:1200px;margin:auto;padding:16px 24px;border-bottom:1px solid #1d3339;gap:12px}.brand{font-size:21px;font-weight:800;color:#fff;text-decoration:none;letter-spacing:-.035em}.nav-right{display:flex;gap:8px}.badge,.status{display:inline-flex;align-items:center;font-size:11px;border:1px solid #315058;border-radius:999px;padding:6px 10px;color:#b9ced3;background:#0b181d}main{max-width:1200px;margin:auto;padding:32px 24px 64px}.hero{max-width:1050px;padding:42px 0 48px}.eyebrow,.kicker{font-size:11px;letter-spacing:.15em;color:#91bac3;font-weight:800;margin:0 0 12px}.hero h1{font-size:clamp(40px,6.5vw,78px);line-height:1.03;letter-spacing:-.055em;margin:0}.lead{font-size:20px;color:#a9c0c6;max-width:820px;margin:24px 0}.flow{display:flex;flex-wrap:wrap;gap:9px;align-items:center;margin-top:28px}.flow span{padding:8px 11px;background:#0b171c;border:1px solid #254149;border-radius:9px;color:#a9bec3;font-size:13px}.flow b{color:#55767e}.workspace{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(280px,.65fr);gap:18px;margin-bottom:18px}.panel{border:1px solid #203940;background:rgba(8,20,25,.88);border-radius:18px;padding:24px;min-width:0}.live-panel{margin-bottom:18px;border-color:#365f68;background:linear-gradient(135deg,rgba(11,31,36,.96),rgba(7,20,24,.9))}.panel-head{display:flex;justify-content:space-between;gap:18px;align-items:flex-start}.panel h2{font-size:26px;letter-spacing:-.03em;margin:0 0 18px}.metric{border-top:1px solid #213840;padding:14px 0;display:grid;gap:3px}.metric strong{font-size:14px}.metric span,.muted{color:#a0b6bc;font-size:14px}label{display:grid;gap:7px;font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:#a7bfc5;margin:12px 0;min-width:0}input{width:100%;min-width:0;border:1px solid #29474f;border-radius:10px;background:#061014;color:#eef5f6;padding:12px 13px;font:inherit;text-transform:none;letter-spacing:0}input:focus-visible,button:focus-visible{outline:2px solid #a3d6df;outline-offset:3px}input:disabled{opacity:.75}.row{display:grid;grid-template-columns:1fr 1fr;gap:12px}.row.three{grid-template-columns:.7fr 1.2fr .7fr}button{border:0;border-radius:10px;background:#e6f0f1;color:#061014;padding:12px 16px;font-weight:800;cursor:pointer;margin:6px 6px 0 0}button:disabled{cursor:not-allowed;opacity:.45}.secondary{background:#193740;color:#d8e9ed;border:1px solid #365963}.summary{display:grid;gap:4px;margin-top:18px;padding:15px;border:1px solid #2c4b53;border-radius:12px;background:#08171b}.output{min-height:150px;max-height:360px;overflow:auto;background:#040b0d;border:1px solid #1a3036;border-radius:10px;padding:14px;color:#b2d1d7;font-size:12px;white-space:pre-wrap;overflow-wrap:anywhere}.timeline{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px;margin-top:22px}.timeline-empty,.timeline-error{grid-column:1/-1;padding:18px;border:1px dashed #315059;border-radius:12px;color:#a1b9bf}.timeline-error{border-color:#704047;color:#efbec2}.timeline-step{border:1px solid #29474e;border-radius:12px;padding:14px;background:#071519;min-width:0}.timeline-step strong,.timeline-step span{display:block}.timeline-step strong{font-size:14px;margin-bottom:5px}.timeline-step span{font-size:12px;color:#a1bac1}.timeline-step code,.receipt code{display:block;overflow-wrap:anywhere;font-size:11px;margin:5px 0;color:#c1dce2}details{margin-top:8px}summary{cursor:pointer;font-size:12px}.receipt{margin-top:16px;padding:20px;border:1px solid #47717a;border-radius:14px;background:rgba(15,38,44,.72);overflow-wrap:anywhere}.hidden{display:none}.receipt h3{margin:0 0 15px;font-size:22px}.receipt-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px}.receipt-grid span,.receipt-grid strong{display:block}.receipt-grid span{font-size:11px;color:#a2bdc5}.receipt-grid strong{font-size:13px;margin-top:4px}.negative{border-top:1px solid #35565e;margin-top:12px;padding-top:12px}footer{max-width:1200px;margin:auto;padding:24px;border-top:1px solid #1d3339;color:#98b0b7;font-size:12px}@media(max-width:900px){.workspace,.timeline,.receipt-grid,.row,.row.three{grid-template-columns:1fr}.hero{padding-top:18px}.panel-head{display:block}.status{margin-bottom:10px}.panel{padding:20px}main{padding:20px 16px 40px}.nav{padding:14px 16px}.nav-right .badge:last-child{display:none}.eyebrow{line-height:1.8}.lead{font-size:17px}} .readiness-panel,.criteria-panel{margin-bottom:18px}.status.blocked{border-color:#7a6540;color:#e4bc68}.readiness-grid,.criteria-grid{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-top:18px}.readiness-grid>div,.criteria-grid article{border:1px solid #29474f;border-radius:12px;padding:14px;background:#071519;min-width:0}.readiness-grid strong,.readiness-grid span,.criteria-grid strong,.criteria-grid span{display:block}.readiness-grid strong,.criteria-grid strong{font-size:13px;margin-bottom:5px}.readiness-grid span,.criteria-grid span{font-size:12px;color:#a1bac1}.criteria-grid{grid-template-columns:repeat(3,minmax(0,1fr))}@media(max-width:900px){.readiness-grid,.criteria-grid{grid-template-columns:1fr}} .evidence-rail{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin:0 0 18px}.evidence-rail article{border:1px solid #29474f;border-radius:14px;padding:16px;background:linear-gradient(180deg,rgba(11,24,29,.94),rgba(7,21,25,.9));min-width:0}.evidence-rail span,.evidence-rail strong,.evidence-rail small{display:block}.evidence-rail span{font-size:10px;letter-spacing:.12em;text-transform:uppercase;color:#91bac3;font-weight:800}.evidence-rail strong{font-size:18px;letter-spacing:-.02em;margin:6px 0 3px;color:#eef4f5}.evidence-rail small{font-size:12px;color:#a0b6bc}.evidence-rail .runtime-verified{border-color:#3f7161}.evidence-rail .runtime-verified strong{color:#9fe0c4}@media(max-width:900px){.evidence-rail{grid-template-columns:1fr 1fr}}@media(max-width:560px){.evidence-rail{grid-template-columns:1fr}} + +.judge-mode{margin-bottom:18px;border-color:#4f7b6b;background:linear-gradient(135deg,rgba(10,34,29,.94),rgba(7,20,24,.94))} +.judge-story{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:10px;margin-top:18px} +.judge-story article{border:1px solid #355c50;border-radius:14px;padding:16px;background:#081914} +.judge-story b{display:grid;place-items:center;width:28px;height:28px;border-radius:999px;background:#9fe0c4;color:#061014;margin-bottom:12px} +.judge-story strong,.judge-story span{display:block}.judge-story span{font-size:12px;color:#a8c3ba;margin-top:5px} +.judge-actions{margin-top:16px}.passport,.rejection-spotlight{margin-top:16px;border:1px solid #46766a;border-radius:14px;padding:18px;background:#071613} +.passport h3,.rejection-spotlight h3{margin:0 0 14px}.passport-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px} +.passport-grid span,.passport-grid strong,.passport-grid code{display:block}.passport-grid span{font-size:11px;color:#9db8b0}.passport-grid code{font-size:11px;overflow-wrap:anywhere;color:#c3e5da} +.rejection-spotlight{border-color:#84565a;background:linear-gradient(135deg,#241214,#101719)}.rejection-code{font-weight:900;font-size:20px;color:#ffb6bd;margin:8px 0} +@media(max-width:900px){.judge-story,.passport-grid{grid-template-columns:1fr}}