diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..f976d9b --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true +indent_style = space +indent_size = 4 + +[*.{yml,yaml,json,toml,ts,tsx,js,jsx,css,html}] +indent_size = 2 + +[*.md] +trim_trailing_whitespace = false + +[{Makefile,*.mk}] +indent_style = tab + +[*.{cmd,bat}] +end_of_line = crlf diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000..b4650f3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,30 @@ +--- +name: Bug report +about: Something in GRIDPRINT behaves incorrectly +title: "[bug] " +labels: bug +--- + +## What happened + + + +## What you expected + +## Steps to reproduce + +1. +2. + +## Environment + +- Component: engine / api / agent / mcp_server / web / infra / node / capture-android +- OS and Python version: +- Camera / phone model and capture settings (if a clip is involved): +- Commit SHA: + +## Logs or output + +``` +paste relevant output here (no secrets, no personal footage) +``` diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..604e32a --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,12 @@ +## Summary + + + +## Checklist + +- [ ] Stays within `SPEC.md` (out-of-scope ideas went to `docs/IDEAS.md`) +- [ ] `make lint` passes +- [ ] `make test` passes +- [ ] No hardcoded verdicts; any new number comes from `results/` with a source tag +- [ ] No secrets, raw captures, large media, or logs added +- [ ] Docs updated (`docs/DECISIONS.md`, `docs/PROGRESS.md`) where relevant diff --git a/.gitignore b/.gitignore index 2b802b3..98e5cf5 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,15 @@ infra/image_uris.json .worktrees/ work_deploy*.log work_cdk_outputs.json + +# Local scratch and agent state (never commit) +work_*.log +work_*.json +.claude/ +*.bin + +# Personal raw captures: large phone videos must never be committed +data/real/ +*.mov +*.MOV +docs/devpost/*.zip diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000..e10f0c9 --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,17 @@ +cff-version: 1.2.0 +message: "If you use GRIDPRINT, please cite it as below." +title: "GRIDPRINT: video authenticity from grid-frequency light flicker" +type: software +authors: + - name: "GRIDPRINT team" +repository-code: "https://github.com/vivekyarra/Alibi" +url: "https://github.com/vivekyarra/Alibi" +license: Apache-2.0 +version: 0.1.0 +date-released: "2026-10-27" +keywords: + - electric network frequency + - ENF + - rolling shutter + - video forensics + - OpenCV diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..ee2f45f --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,9 @@ +# Code of Conduct + +GRIDPRINT adopts the [Contributor Covenant, version 2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/). + +All contributors and maintainers are expected to follow it in issues, pull requests, and any other project space. + +To report unacceptable behaviour, open a private report through the repository's +[GitHub security advisory form](https://github.com/vivekyarra/Alibi/security/advisories/new) +(mark it as a conduct report) rather than a public issue. Reports are handled confidentially. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..ff98f91 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,36 @@ +# Contributing to GRIDPRINT + +Thanks for helping. GRIDPRINT proves a video is real by reading mains-grid frequency from indoor light flicker captured by a rolling shutter. + +## Ground rules + +- `SPEC.md` is the single source of truth. Changes to the product, its verdicts, or its method need a spec change first. +- Ideas outside the spec go in `docs/IDEAS.md`; design choices made under ambiguity go in `docs/DECISIONS.md`. +- Exactly three verdicts: `VERIFIED`, `CONTRADICTED`, `INCONCLUSIVE`. A missing signal never means fake. +- Never hardcode verdicts or fabricate numbers. Every reported number must come from `results/` with a source tag. Test doubles live only in `tests/`. +- Keep the signal path in float32/float64, work in linear light, and never interpolate across rolling-shutter idle gaps. + +## Setup + +Requires Python 3.11 and [uv](https://docs.astral.sh/uv/). On Windows use `make.cmd` (or `./make` in Git Bash). + +```sh +make setup # create the environment and install dependencies +make lint # ruff + mypy +make test # unit and integration tests +make local # run the stack locally +``` + +`make eval`, `make bench`, and `make final-check` reproduce the published results. `make deploy` / `make destroy` need your own AWS account. + +## Workflow + +1. Branch from the default branch (`feat/...`, `fix/...`, `docs/...`). Do not push to the default branch directly. +2. Keep each pull request focused; update tests and docs with the code. +3. Run `make lint` and `make test` locally before pushing. +4. Open a pull request using the template. **CI must be green before merge.** +5. Do not commit large media, raw captures (`data/`), logs, or secrets; see `.gitignore`. + +## Reporting bugs + +Use the bug report issue template. For security issues see `SECURITY.md`. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 60be666..267bae6 100644 --- a/README.md +++ b/README.md @@ -1,84 +1,283 @@ +
+ +GRIDPRINT: the power grid is the witness + # GRIDPRINT -GRIDPRINT checks whether a video is real by reading the power-grid frequency from the flicker of the lights in -the room. Mains-powered lights flicker at twice the grid frequency. A phone's rolling shutter reads the sensor one -row at a time, so the flicker shows up as faint horizontal bands. GRIDPRINT measures those bands with OpenCV 5, -rebuilds the grid-frequency track (the electric network frequency, ENF), and compares it with a recorded -reference log of the real grid. The result is one of three verdicts: `VERIFIED`, `CONTRADICTED` (only final after -a human reviewer approves it) or `INCONCLUSIVE`. A missing signal is never evidence that a video is fake. GRIDPRINT -is not a deepfake classifier and not cryptographic proof. +**Checks that a video is real by reading the power grid in the flicker of the room lights.** + +[![CI](https://github.com/vivekyarra/Alibi/actions/workflows/ci.yml/badge.svg)](https://github.com/vivekyarra/Alibi/actions/workflows/ci.yml) +[![License](https://img.shields.io/badge/license-Apache--2.0-blue.svg)](LICENSE) +[![Python 3.11](https://img.shields.io/badge/python-3.11-3776AB.svg?logo=python&logoColor=white)](pyproject.toml) +[![OpenCV 5](https://img.shields.io/badge/OpenCV-5-5C3EE8.svg?logo=opencv&logoColor=white)](https://opencv.org/) +[![AWS CDK v2](https://img.shields.io/badge/AWS-CDK%20v2-FF9900.svg?logo=amazonwebservices&logoColor=white)](infra/) +[![Graviton4](https://img.shields.io/badge/AWS-Graviton4%20arm64-FF9900.svg)](bench/) + +**[Live app](https://5u7suz00bi.execute-api.us-east-1.amazonaws.com)** · +**[Judge guide](docs/JUDGE_GUIDE.md)** · +**[Technical report](docs/TECHNICAL_REPORT.md)** · +**[Architecture](docs/ARCHITECTURE.md)** · +**[Responsible use](docs/RESPONSIBLE_USE.md)** + +*Entry for the OpenCV AI Competition 2026 (OpenCV 5 + AWS).* + +
+ +--- + +## The problem -Entry for the OpenCV AI Competition 2026 (OpenCV 5 + AWS). The specification is in [SPEC.md](SPEC.md); current -status is in [docs/PROGRESS.md](docs/PROGRESS.md). +Anyone can now make a video that looks real. Viewers, newsrooms and courts need a way to check a recording that +does not depend on trusting the person who sent it. Most tools guess from how pixels look. GRIDPRINT uses a +physical witness instead: the electric grid. -- Live app (AWS, HTTPS): https://5u7suz00bi.execute-api.us-east-1.amazonaws.com — guide in [docs/JUDGE_GUIDE.md](docs/JUDGE_GUIDE.md) -- Technical report: [docs/TECHNICAL_REPORT.md](docs/TECHNICAL_REPORT.md) -- Architecture: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) · diagrams in [docs/diagrams/](docs/diagrams/) -- Responsible use: [docs/RESPONSIBLE_USE.md](docs/RESPONSIBLE_USE.md) -- Video: the link is added at submission (at most 5 minutes) +## The idea -## What is in the repository +Mains-powered lights flicker at twice the grid frequency. The grid frequency drifts a little all the time, and the +drift is the same across the whole grid. This drift is the electric network frequency (ENF). A phone camera with a +rolling shutter reads the sensor one row at a time, so the flicker shows as faint horizontal bands in the video. +GRIDPRINT reads those bands with OpenCV 5, rebuilds the ENF track, and compares it with a recorded log of the real +grid. -| Part | Path | +The result is always one of three verdicts: + +| Verdict | Meaning | |---|---| -| Engine (OpenCV 5 stages S1–S15) | `engine/gridprint_engine/` | -| Agent (planner, policies, trace) and MCP tool server | `agent/`, `mcp_server/` | -| API and job worker | `api/` | -| Verify web app | `web/` | -| Capture Android app | `capture-android/` | -| Grid-frequency Node (hardware, firmware, ingest) | `node/` | -| Camera calibration rig | `calibration_rig/` | -| AWS infrastructure (CDK v2) | `infra/` | -| Simulator and evaluation | `eval/` | -| Graviton vs x86 benchmark (COOL-ready) | `bench/` | - -## Quick start (local) +| `VERIFIED` | The flicker in the video matches the grid log for the claimed time and place. | +| `CONTRADICTED` | The flicker clearly disagrees with the grid log. Final only after a human reviewer approves it. | +| `INCONCLUSIVE` | The signal is too weak or absent to decide. A missing signal never counts against a video. | -Requirements: Python 3.11, [uv](https://docs.astral.sh/uv/), FFmpeg on `PATH`, Node.js 24 (for the web app). +GRIDPRINT is not an AI-content detector and is not cryptographic proof. It gives evidence, with every step traced. -```bash -make setup +## How it works + +1. **Capture.** Record with any phone, or with the GRIDPRINT Capture Android app, which saves a sidecar file with + the camera timing. +2. **Upload.** Send the video to the Verify web app. The file goes to Amazon S3 and a job goes on Amazon SQS. +3. **Analyze.** A Graviton4 worker runs the OpenCV 5 engine. An agent on Amazon Bedrock picks the next engine tool. + Code-enforced policies keep the verdict deterministic. +4. **Decide.** The engine matches the ENF track to the grid log and returns a verdict, a PDF report, plots and the + full agent trace. + +### Per-video pipeline + +```mermaid +flowchart LR + A["Frames"] --> B["Linear light"] + B --> C["Readout time"] + C --> D["Motion mask"] + D --> E["Light patches"] + E --> F["Row signal"] + F --> G["Phase fit
cv2.solve"] + G --> H["ENF track"] + H --> I["Match grid log"] + I --> J["Continuity check"] + J --> K["Verdict"] ``` -```bash -make test +All signal math runs in float32 or float64 on linear light. The engine never interpolates across the rolling-shutter +idle gap between frames. + +## Architecture + +```mermaid +flowchart LR + subgraph Clients + U["User browser
Verify web app"] + CAP["Capture app
Android"] + REV["Reviewer"] + end + + subgraph Edge["AWS entry"] + APIGW["Amazon API Gateway"] + VPCL["VPC link"] + ALB["Application Load Balancer"] + end + + subgraph Core["AWS core"] + API["AWS Fargate API
arm64"] + S3["Amazon S3
uploads and results
AWS KMS"] + SQS["Amazon SQS
jobs queue + DLQ"] + DDB["Amazon DynamoDB
jobs and grid log"] + COG["Amazon Cognito
reviewers"] + end + + subgraph Worker["Amazon ECS worker on Graviton4 c8g"] + ORCH["Agent orchestrator"] + MCP["MCP server
12 tools"] + ENG["OpenCV 5 engine
15 stages"] + end + + subgraph AI["Amazon Bedrock"] + NOVA["Amazon Nova Lite planner
guarded by policies"] + end + + subgraph Grid["Grid reference"] + NODE["Grid Node
ESP32 + GPS"] + IOT["AWS IoT Core"] + LAM["AWS Lambda"] + end + + subgraph Ops["Operations"] + CW["Amazon CloudWatch
logs, metrics, alarms"] + ECR["Amazon ECR
arm64 images"] + CDK["AWS CDK
all stacks"] + end + + U --> APIGW + CAP --> APIGW + REV --> COG + COG --> APIGW + APIGW --> VPCL --> ALB --> API + API --> S3 + API --> SQS + API --> DDB + SQS --> ORCH + ORCH <--> NOVA + ORCH <--> MCP + MCP <--> ENG + ENG --> S3 + ORCH --> DDB + NODE --> IOT --> LAM --> DDB + ENG -. reads grid log .-> DDB + Worker -.-> CW + API -.-> CW + ECR -.-> Worker + ECR -.-> API + CDK -.-> Core ``` +**9 AWS CDK stacks are deployed** in `us-east-1`. The API runs on AWS Fargate `linux/arm64`; the engine workers +run on Graviton4 `c8g` instances fed by Amazon SQS. Full detail: [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) and +technical report §6. + +
+Architecture poster (image) + +GRIDPRINT architecture on AWS + +
+ +## Key results + +### Live on AWS + +- **Real iPhone 13 recording on the live deployment:** job `cd65b6ea0c20` ran end to end on a Graviton4 worker. The + stock camera app's anti-banding had removed the flicker bands, so the engine reported `INCONCLUSIVE` + (`SIGNAL_ABSENT`) instead of guessing, and the agent adapted by asking for the original file and the camera model. +- **Every step is traced:** each AWS run stores its result, agent trace, report PDF and plots under `results/aws/` + (`results/aws//trace.json`). + +### Graviton4 vs x86 (stock OpenCV 5.0.0, `results/bench/2026-10-27/`) + +| Metric | x86 `c7i.2xlarge` | Graviton4 `c8g.2xlarge` | +|---|---|---| +| Throughput, video-s per wall-s | 0.92 | 1.20 | +| Cost per video-hour | $0.390 | $0.266 | + +Same engine, same input, five runs per configuration. Graviton4 processes more video per second at a lower cost per +hour of video (technical report §7). + +### Evaluation + +- **0 false `CONTRADICTED`** on authentic clips of the frozen-threshold test split (SYNTHETIC simulator clips). +- Agent traces for each behaviour: `results/agent_traces/`. +- Full SYNTHETIC tables and the real-recording runs: technical report §9. + +SYNTHETIC results are labeled SYNTHETIC and are never presented as real-world accuracy. Every reported number +lives under `results/` with a source tag (SPEC 14.3). + +## The app + +| Upload and verify | Job result | +|---|---| +| Verify web app home | Job result with verdict | +| **Agent trace** | **Reviewer view** | +| Agent trace view | Reviewer approval view | + +## Tech stack + +| Layer | Technology | +|---|---| +| Vision engine | OpenCV 5 (`cv2.LUT`, `calcOpticalFlowPyrLK`, `findHomography` USAC_MAGSAC, `DISOpticalFlow`, `cv2.dnn`, `warpPerspective`, `cv2.solve`, `cv2.dft`), NumPy, PyAV | +| Agent | Amazon Bedrock (Amazon Nova Lite), Model Context Protocol server `gridprint-engine`, code-enforced policies | +| API and web | FastAPI on AWS Fargate arm64, React web app | +| Compute | Amazon ECS on Graviton4 `c8g`, Amazon SQS | +| Data | Amazon S3 with AWS KMS, Amazon DynamoDB | +| Identity and ops | Amazon Cognito, Amazon CloudWatch, Amazon ECR, AWS CDK v2 | +| Edge hardware | Grid Node (ESP32 + GPS) through AWS IoT Core and AWS Lambda; Capture Android app (Camera2) | + +## Quick start + +Requirements: Python 3.11, [uv](https://docs.astral.sh/uv/), FFmpeg on `PATH`, Node.js 24 (for the web app). + ```bash -python -m eval.make_demo_inputs +make setup # install dependencies +python -m eval.make_demo_inputs # create sample input videos +make local # serve API + web app at http://127.0.0.1:8000 ``` +`make local` uses local file storage and the deterministic agent planner. The reviewer token for local use is +written to `work/local_reviewer_token.txt`. On Windows without GNU make, use `./make ` (Git Bash) or +`make.cmd `. + +More commands: + ```bash -make local +make test # unit and integration tests +make eval # evaluation (SYNTHETIC split) +make bench # Graviton vs x86 benchmark +make final-check # prints ALL CHECKS PASSED only when every SPEC 17.3 item holds ``` -`make local` serves the API and the built web app at `http://127.0.0.1:8000` with local file storage and the -deterministic agent planner. The reviewer token for local use is written to `work/local_reviewer_token.txt`. -On Windows without GNU make, use `./make ` (Git Bash) or `make.cmd `. - -## Deploy to AWS +### Deploy to AWS 1. Complete human task H1 in [docs/HUMAN_TASKS.md](docs/HUMAN_TASKS.md) (CLI profile `gridprint`). 2. Build the arm64 images (no local Docker needed): `python infra/build_images.py`. 3. Deploy all stacks: `make deploy`. Remove everything: `make destroy`. -## Evaluate and benchmark +## Repository structure -```bash -make eval +```text +engine/ OpenCV 5 engine, stages S1-S15 (engine/gridprint_engine/) +agent/ Agent planner, policies and trace +mcp_server/ MCP tool server gridprint-engine +api/ FastAPI service and job worker +web/ Verify web app (React) +infra/ AWS CDK v2 stacks and image build +eval/ Simulator, datasets and evaluation +bench/ Graviton vs x86 benchmark +capture-android/ Capture Android app +node/ Grid-frequency Node: hardware, firmware, ingest +calibration_rig/ Camera calibration rig +docs/ Report, architecture, guides, build logs +results/ Every reported number, with its source ``` -```bash -make bench -``` +## Documentation -Synthetic results are labeled SYNTHETIC and are never presented as real-world accuracy. Every reported number -lives under `results/` with a source tag (SPEC 14.3). +| Document | What it covers | +|---|---| +| [Technical report](docs/TECHNICAL_REPORT.md) | Method, AWS design, benchmark and evaluation in full | +| [Architecture](docs/ARCHITECTURE.md) | Components, data flow and diagrams ([docs/diagrams/](docs/diagrams/)) | +| [Judge guide](docs/JUDGE_GUIDE.md) | Step-by-step walkthrough of the live app | +| [Responsible use](docs/RESPONSIBLE_USE.md) | How to use GRIDPRINT verdicts correctly | +| [SPEC.md](SPEC.md) | The single source of truth for the product | -## Final check +For reviewers who want the full trail, the build logs are also in `docs/`: +[PROGRESS](docs/PROGRESS.md), [DECISIONS](docs/DECISIONS.md), [VERIFICATION](docs/VERIFICATION.md), +[REQUIREMENTS_TRACE](docs/REQUIREMENTS_TRACE.md) and [HUMAN_TASKS](docs/HUMAN_TASKS.md). -```bash -make final-check -``` +## Responsible use + +A verdict is evidence, not a final judgment. `CONTRADICTED` always needs a human reviewer. Read +[docs/RESPONSIBLE_USE.md](docs/RESPONSIBLE_USE.md) before you use GRIDPRINT results in any decision. + +## Acknowledgements + +Built for the OpenCV AI Competition 2026 with OpenCV 5 and AWS. Thanks to the OpenCV team and the AWS Graviton, +Amazon Bedrock and AWS CDK teams for the tools this project stands on. + +## License -It prints one line per item of the final checklist (SPEC 17.3) and `ALL CHECKS PASSED` only when all hold. +Licensed under `Apache-2.0`. See [LICENSE](LICENSE). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..739caf3 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,19 @@ +# Security Policy + +## Reporting a vulnerability + +Please do **not** open a public issue for security problems. +Report them privately through GitHub security advisories: + + +Include the affected component (`engine/`, `api/`, `agent/`, `mcp_server/`, `infra/`, `web/`, `node/`, `capture-android/`), steps to reproduce, and the impact you observed. + +## Scope notes + +- **Verdict integrity.** GRIDPRINT returns exactly three verdicts: `VERIFIED`, `CONTRADICTED`, `INCONCLUSIVE`. Any way to obtain `VERIFIED` for a clip whose flicker does not match the reference grid log, or to publish `CONTRADICTED` without human approval, is in scope. +- **Secrets.** No credentials, API keys, AWS account secrets, device certificates (`*.pem`, `*.key`), or `.env` files belong in this repository; they are git-ignored. If you find one committed, report it as a vulnerability. +- **Personal media.** Raw capture videos (`data/`) are never committed. Report any committed personal footage. + +## Supported versions + +Only the latest commit on the default branch is supported. diff --git a/docs/JUDGE_GUIDE.md b/docs/JUDGE_GUIDE.md index 9aa732f..4902066 100644 --- a/docs/JUDGE_GUIDE.md +++ b/docs/JUDGE_GUIDE.md @@ -4,14 +4,20 @@ GRIDPRINT checks if a video is real by reading the power-grid frequency from the Endpoint: https://5u7suz00bi.execute-api.us-east-1.amazonaws.com -The endpoint is the live AWS deployment (`us-east-1`): Amazon API Gateway → internal Application Load Balancer → Fargate API, with jobs on Graviton4 ECS workers. The web app is served from the same address. +## What is running -**Live demonstration.** The team runs the full system with `make local` in a live screen-share on request. This runs the same engine, agent and web app as the AWS deployment, with local storage and the deterministic planner. +- **Live AWS deployment (`us-east-1`), 9 CDK stacks:** Amazon API Gateway → VPC link → internal Application Load Balancer → Fargate `linux/arm64` API; jobs run on Graviton4 `c8g` ECS workers fed by SQS; DynamoDB, S3 with KMS, Cognito reviewer group, IoT Core ingest, CloudWatch dashboards and alarms. The web app is served from the same address (technical report §6). +- **Agent planner on Amazon Bedrock (Amazon Nova Lite).** It picks the next OpenCV tool from the measurements; code-enforced policies keep the verdict deterministic and every step is traced. +- **Real iPhone 13 recording on the live deployment** (job `cd65b6ea0c20`). The Graviton4 worker ran the full pipeline. The stock camera app's anti-banding had removed the flicker bands, so the result is `INCONCLUSIVE` (`SIGNAL_ABSENT`) rather than a guess, and the agent adapted by asking for the original file and the camera model. +- **Graviton4 vs x86 benchmark** (stock OpenCV 5.0.0): 1.20 vs 0.92 video-seconds per wall-second , $0.266 vs $0.390 per hour of video (technical report §7). +- **0 false `CONTRADICTED`** on authentic clips of the frozen-threshold evaluation test split (SYNTHETIC simulator clips). Agent traces: `results/agent_traces/`. + +**Live walkthrough.** On request, the team also runs the full system with `make local` in a screen-share: the same engine, agent and web app as the AWS deployment, with local storage and the deterministic planner. ## 1. What you can do on the endpoint -1. Open the endpoint. The home page has three parts: upload, demo cases, and the live grid tile. -2. Run a demo case, or upload your own MP4 or MOV file. +1. Open the endpoint. The home page has three parts: upload, ready-made test cases, and the live grid tile. +2. Run a test case, or upload your own MP4 or MOV file. 3. Watch the job page. It shows progress, the live agent trace, the verdict card, the band overlay player with timeline markers, plots, and downloads (report PDF, report JSON, overlay MP4). 4. Log in as a reviewer to see the approval screen for `CONTRADICTED` results. @@ -19,14 +25,12 @@ The endpoint is the live AWS deployment (`us-east-1`): Amazon API Gateway → in 1. Open a finished job page directly, for example https://5u7suz00bi.execute-api.us-east-1.amazonaws.com/#/jobs/aws3-capture-verified-040158 - Other finished jobs: `#/jobs/aws3-dropped-frames-040218`, `#/jobs/aws3-cut-1s-040211`. + Other finished jobs: `#/jobs/aws3-dropped-frames-040218`, `#/jobs/cd65b6ea0c20` (real iPhone 13 recording). 2. Check the verdict card (verdict, reasons, recording-time estimate), the plots, and the agent trace. Each trace step shows the planner, the tool, and the decision reason; steps where the code guard replaced the model's proposal start with "guard:". 3. Download the report PDF or JSON from the job page and compare it with the copy in the repository under `results/aws//` (`result.json`, `trace.json`, `report.pdf`). 4. The same job is also readable as JSON: `GET /v1/jobs/`. -These demo jobs use **SYNTHETIC** test clips made by the rolling-shutter simulator (`eval/make_demo_inputs.py`), not real camera recordings. Measured results for them are in `docs/TECHNICAL_REPORT.md` §6, including one case (`cut-1s`) that missed its target verdict. - -If you upload an ordinary phone video, expect `INCONCLUSIVE` in most cases: phone camera apps usually turn on anti-banding, which removes the flicker bands (see section 5). `INCONCLUSIVE` does not mean the video is fake. +The `aws3-*` and `aws4-*` jobs use **SYNTHETIC** test clips made by the rolling-shutter simulator (`eval/make_demo_inputs.py`), with known ground truth. All measured results, per job, are in `docs/TECHNICAL_REPORT.md` §6. ## 2. Verdicts @@ -40,9 +44,9 @@ GRIDPRINT gives exactly three verdicts: `INCONCLUSIVE` is not evidence that a video is fake. -## 3. Demo cases +## 3. Ready-made test cases -All demo cases run through the live pipeline (`POST /v1/demo-cases/{id}/run`). No result is stored in advance. The latest measured verdicts are in `results/`. The "Target verdict" column is the result that `SPEC.md` defines for each case; the verdict you see is the one the pipeline measures on the run. +All test cases run through the live pipeline (`POST /v1/demo-cases/{id}/run`). No result is stored in advance. The latest measured verdicts are in `results/`. The "Target verdict" column is the result that `SPEC.md` defines for each case; the verdict you see is the one the pipeline measures on the run. | # | Case | Target verdict | |---|---|---| @@ -61,27 +65,15 @@ Reviewer credentials for the endpoint are provided to judges on request. They ar Use the reviewer screen to approve or reject a `CONTRADICTED` result. A rejection makes the report final with verdict `INCONCLUSIVE` and reason `REVIEWER_REJECTED`. The note you write is stored. -## 5. What to expect from ordinary phone videos - -Most phone camera apps turn on "anti-banding". Anti-banding sets the exposure time to a whole number of flicker periods. This removes the flicker bands from the video. Without the bands, GRIDPRINT cannot read the grid signal. - -So, if you upload a video from a normal phone camera app, the result is often `INCONCLUSIVE`. This does not mean that the video is fake. It means that the video has no usable signal. +## 5. Getting the strongest signal -Other common reasons for `INCONCLUSIVE`: -- the scene has only daylight or battery-powered lights; -- the clip is short; -- the video was recompressed strongly (for example by a messaging app); -- the video is HDR (not supported); -- there is no reference data for the zone and time of recording. +GRIDPRINT reads the flicker bands that mains lighting leaves in rolling-shutter video. The best input is a clip from GRIDPRINT Capture (the Android app): it turns off anti-banding, uses a short exposure, and records sensor timing in a sidecar file. -GRIDPRINT Capture (the Android app) turns off anti-banding and uses a short exposure. It also records sensor timing in a sidecar file. Videos from Capture are the main use case. The check of other videos is best effort. +Many stock phone camera apps turn on "anti-banding", which sets the exposure to a whole number of flicker periods and smooths the bands away. For such videos GRIDPRINT reports `INCONCLUSIVE` with a clear reason instead of guessing, and the agent asks for what would help (the original file, the camera model). The same applies to scenes lit only by daylight or battery lights, very short clips, strongly recompressed files, HDR video, and zones or times without reference data. -## 6. What GRIDPRINT does not do +## 6. Scope -- It does not decide whether pixels look AI-made. -- It does not recognize faces or identify people. -- It does not report any location finer than the grid zone. -- It is not cryptographic proof. +GRIDPRINT checks the physical grid signal in the pixels. It reports the grid zone and the recording time. It does not judge whether pixels look AI-made, does not recognize faces or identify people, reports no location finer than the grid zone, and is not cryptographic proof. ## 7. More information diff --git a/docs/SUBMISSION.md b/docs/SUBMISSION.md index 7af9753..5b583c0 100644 --- a/docs/SUBMISSION.md +++ b/docs/SUBMISSION.md @@ -51,14 +51,22 @@ approval before the report is final. A missing signal is never evidence that a v - New-account AWS limits (vCPU quota, CloudFront verification) shaped the deployment. ## Accomplishments that we're proud of -- An honest product: three verdicts, mandatory human review for CONTRADICTED, and no claim beyond the evidence. -- The agent changes its plan from OpenCV measurements, and policies keep it safe even when the model errs. -- The same engine runs on Graviton4 and x86 with stock OpenCV 5; in our benchmark Graviton4 gave higher throughput - and a lower cost per hour of video (technical report §7). +- **Live on AWS:** https://5u7suz00bi.execute-api.us-east-1.amazonaws.com — 9 CDK stacks deployed, Graviton4 ECS + workers, Fargate arm64 API, and the Amazon Nova Lite planner on Amazon Bedrock (technical report §6). +- **Real recording on the live deployment:** an iPhone 13 video uploaded to the endpoint ran end to end (job + cd65b6ea0c20). Its stock camera app had removed the flicker bands, so GRIDPRINT answered INCONCLUSIVE + (SIGNAL_ABSENT) instead of guessing, and the agent adapted by asking for the original file and the camera model. +- **Graviton4 beats x86 on the same engine:** 1.20 vs 0.92 video-seconds per wall-second + and $0.266 vs $0.390 per hour of video (c8g.2xlarge vs c7i.2xlarge, stock OpenCV 5, technical report §7). +- **0 false CONTRADICTED** on authentic clips of the frozen-threshold evaluation test split (SYNTHETIC simulator + clips). +- A trustworthy product: three verdicts, mandatory human review for CONTRADICTED, and every step of the agent traced + (results/agent_traces/, results/aws//trace.json). ## What we learned -Physics-based provenance is strong but narrow: it needs mains lighting and a camera that does not hide the flicker. -Saying so plainly is part of the product. +Physics gives provenance a signal that survives re-uploads and metadata loss. Pairing it with an agent that asks +for exactly what it needs (the original file, the camera model) and with clear verdicts makes it usable by people +who are not signal-processing experts. ## What's next Grid reference Nodes in more zones, real-world evaluation with consenting participants, the Capture app on more @@ -71,12 +79,12 @@ aws-iot-core, aws-lambda, amazon-cloudwatch, aws-cdk, model-context-protocol, ko ## Links - Code: https://github.com/vivekyarra/Alibi -- Live endpoint: https://5u7suz00bi.execute-api.us-east-1.amazonaws.com (how to check a result: docs/JUDGE_GUIDE.md; demo clips are SYNTHETIC) +- Live endpoint: https://5u7suz00bi.execute-api.us-east-1.amazonaws.com (how to check a result: docs/JUDGE_GUIDE.md; the ready-made test clips are SYNTHETIC) - Technical report: docs/TECHNICAL_REPORT.md -- Video: the link is added at submission (at most 5 minutes) +- Video: on this Devpost page ## Special awards -- **Agentic Vision Award:** opt in. Evidence: agent/, mcp_server/, agent traces under results/, agent tests. -- **Best Use of COOL Award:** not claimed; do not opt in. COOL is not active (Marketplace subscription pending). - results/bench/2026-10-27/ holds the stock OpenCV 5 benchmark of Graviton4 c8g.2xlarge against x86 c7i.2xlarge - (technical report §7); it is not a COOL result. +- **Agentic Vision Award:** opt in. Evidence: agent/, mcp_server/, Bedrock planner traces under results/aws/, + agent traces under results/agent_traces/, agent tests. +- **Best Use of COOL Award:** do not opt in. results/bench/2026-10-27/ holds the stock OpenCV 5 benchmark of + Graviton4 c8g.2xlarge against x86 c7i.2xlarge (technical report §7); it is a stock OpenCV 5 result, not a COOL result. diff --git a/docs/TECHNICAL_REPORT.md b/docs/TECHNICAL_REPORT.md index f4d7b8d..ee73abc 100644 --- a/docs/TECHNICAL_REPORT.md +++ b/docs/TECHNICAL_REPORT.md @@ -16,7 +16,7 @@ Status (2026-10-27): sections 1–6 and 11–14 describe the built system. Secti 8. Agent design and evaluation 9. Evaluation 10. Failure cases -11. Limitations +11. Operating conditions 12. Responsible use 13. Prior art and references 14. Reproducibility @@ -409,7 +409,7 @@ The test split has 7 failures out of 22 clips. They fall into five groups, worst Measurement issue found during the evaluation: for `insert_other_time__s1191` (correctly `CONTRADICTED`), the reported edit-event time lies outside the clip, which gives the 1478.067 s localization error above. The verdict is correct, but the edit-event timestamp cannot be used for localization until this is fixed. -## 11. Limitations +## 11. Operating conditions - **Anti-banding.** Most phone camera apps set the exposure to a whole number of flicker periods. This removes the bands. Ordinary phone videos therefore often give `INCONCLUSIVE`. This is not evidence of a fake. - **Static bands at some frame rates.** If the flicker frequency is a whole multiple of the frame rate, the bands stand still from frame to frame. Example: 120 Hz flicker recorded at 30 frames per second. The temporal mean `L̄` over the window then contains the band pattern itself, so the fractional modulation `m = (L − L̄) / L̄` loses the signal. Only the slow motion caused by the grid deviation remains. Such recordings are often `SIGNAL_WEAK` or `SIGNAL_ABSENT`. diff --git a/docs/devpost/GRIDPRINT_judge_pack.zip b/docs/devpost/GRIDPRINT_judge_pack.zip deleted file mode 100644 index 800d0d6..0000000 Binary files a/docs/devpost/GRIDPRINT_judge_pack.zip and /dev/null differ