# Project export: AI Time Machine

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: Time to reconstructs the hidden story behind your code — from commits and PRs to bugs, decisions, and architectural evolution.
- Devpost: https://devpost.com/software/ai-time-machine
- GitHub: https://github.com/ved-devAI/AI_Time_Machine
- Demo: https://ai-time-machine-demo.vedheshvit.chatgpt.site/
- Video: https://www.youtube.com/embed/5LGXtmJNO0U?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — ved-devAI (13 commits)

## Devpost submission (written by the team)

### Inspiration

Git records what changed, but the reasoning behind those changes is often scattered across commit messages, issue references, tests, and source files. When a bug appears, developers can spend hours reconstructing why a risky decision was introduced and how the code evolved afterward. AI Time Machine was inspired by a simple question: What if a repository could explain its own history?

### What it does

AI Time Machine transforms real Git history into an interactive, evidence-backed story of how a codebase evolved. Developers can: Explore commits through a visual timeline. Ask questions about the repository in Ask the Repo. Open citations and inspect the exact supporting event, commit, and affected files. Use Bug Origin Trace to follow a problem from its introduction through discovery and resolution. See whether a statement is confirmed evidence, an inference, or information that was not recorded. Analyze another local Git worktree using Real Repo Mode. The flagship OrbitCart demonstration traces a stale-price checkout bug through its complete history: a latency problem, the introduction of an unsafe cache, issue OC-52, rollback, a catalog-version fix, and the regression test that protected the final solution. OrbitCart is a synthetic demonstration project, but it is stored as a genuine Git repository with 12 real commits that the application analyzes. How I built it The project uses Python 3.11 and Git for repository ingestion. Commit metadata, changed files, issue references, and diffs are normalized into an evidence model consumed by the application. The interface is built with JavaScript, HTML, and CSS. It provides the timeline, Ask the Repo results, citation navigation, Bug Origin Trace, repository evidence views, and responsive desktop and mobile layouts. Generated analysis is stored using a strict artifact format. Before an artifact is displayed, the application validates its schema, repository evidence digest, event references, commit references, and affected-file relationships. The public demonstration is a deterministic, zero-key deployment. It does not require an OpenAI API key or make a paid model call when someone opens the site. Real Repo Mode can also run locally using only Python and Git. How I used Codex and GPT-5.6 Codex was used throughout the project for architecture exploration, implementation, debugging, test creation, UI refinement, trust-semantics review, and evaluation. GPT-5.6 Sol was used through ChatGPT-authenticated Codex as a build-time analysis tool. It generated the committed OrbitCart causal-analysis and Ask the Repo artifacts from repository evidence. The hosted application does not claim that these responses are generated live. It replays the committed artifacts only after their evidence references have been validated. If an artifact is missing or invalid, the product falls back transparently to deterministic repository analysis instead of presenting unsupported model output. Challenges I faced The largest challenge was separating causality from correlation. A commit appearing before a bug does not automatically prove that it caused the bug. Every explanation therefore needed to retain its connection to observable Git evidence. Another challenge was making citations trustworthy. Checking that a commit exists was not sufficient; the application also needed to ensure that referenced events and files belonged to the correct evidence context. I also wanted the public demo to remain reliable for every reviewer without requiring API credits, authentication, or a network-dependent model response. This led to the build-time artifact and runtime-validation architecture. Finally, arbitrary repositories often contain incomplete commit messages. AI Time Machine handles that honestly: missing rationale or risk is displayed as not recorded instead of being invented. Accomplishments that I am proud of Built an interactive evidence timeline from real Git history. Created clickable Ask the Repo citations that open the supporting timeline event. Built a complete visual Bug Origin Trace. Added Real Repo Mode for analyzing other local Git worktrees. Added strict artifact and evidence-reference validation. Kept the hosted experience deterministic and API-key-free. Created 51 application tests plus an OrbitCart regression suite. Achieved 15/15 on the deterministic grounding regression scorecard. Verified the project using automated tests, artifact validators, browser-flow checks, JavaScript validation, and GitHub Actions. What I learned The most important lesson was that citations alone do not make an AI explanation trustworthy. The application must validate what those citations point to and communicate the limits of the evidence. I also learned that uncertainty is part of a useful developer tool. Saying not recorded can be more valuable than generating a confident but unsupported explanation. Git history provides a strong factual boundary for AI-assisted code archaeology because claims can be linked back to concrete commits, files, and events.

### What's next

Future work includes more complete merge, rename, and merge-base handling; bounded diff evidence; stronger semantic validation of generated claims; performance improvements for large repositories; and optional local-first connectivity for teams that want to generate new analysis artifacts. Try it Public demo: https://ai-time-machine-demo.vedheshvit.chatgpt.site Source code: https://github.com/ved-devAI/AI_Time_Machine The hosted demo works in a modern desktop or mobile browser. For local testing, install Python 3.11+ and Git, then run: Then open http://127.0.0.1:8000. The local workflow has been verified on macOS and through GitHub Actions on Linux.

## README (from the GitHub repository)

# AI Time Machine

AI Time Machine turns real Git history into an interactive, evidence-backed
timeline explaining why a codebase evolved.

**Public demo:** <https://ai-time-machine-demo.vedheshvit.chatgpt.site>

**Demo video:** <https://youtu.be/5LGXtmJNO0U>

![AI Time Machine project thumbnail](frontend/project-thumbnail.png)

This repository contains an OpenAI Build Week developer tool: a generated
OrbitCart Git repository, Git ingestion, an evidence timeline, reference-validated
GPT-5.6-in-Codex artifacts, Ask the Repo, and a visual Bug Origin Trace.

## How Codex and GPT-5.6 were used

Codex supported architecture exploration, implementation, debugging, UI
refinement, test development, trust-semantics review, and grounding evaluation.

GPT-5.6 Sol was used through ChatGPT-authenticated Codex to generate the
committed OrbitCart causal-analysis and Ask the Repo artifacts from repository
evidence. This generation happened at build time.

The hosted application does not call GPT-5.6 live. It replays an artifact only
after validating its evidence digest, event IDs, commit references, and affected
files. If validation fails, the application uses a clearly labeled deterministic
fallback instead of displaying unsupported model output.

## Real Repo Mode

Point the local tool at any Git worktree. The required flow uses only Python and
Git; it does not require GitHub OAuth, an OpenAI API key, or a paid runtime call.

```bash
python3 -m app.cli analyze /path/to/repository
python3 -m app.cli analyze /path/to/repository --branch feature/my-work
python3 -m app.cli serve /path/to/repository
python3 -m app.cli serve --open
python3 -m app.cli context /path/to/repository --base main --head HEAD
```

`analyze` prints the normalized timeline JSON and supports `--output`. `serve`
opens the existing interface at <http://127.0.0.1:8765> with the selected
repository fixed at process start. `context` reports changed files, commits in
the range, recent commits touching those files, connected incidents or fixes,
and risks that Git actually records.

For ordinary repositories, the Developer Workspace adds a visual **Review my
branch** report and four adaptive deterministic questions. Their answers cite
clickable commits and same-event files and are labeled `Local evidence engine ·
deterministic`; they are not GPT output. `serve` defaults to the current
worktree, and `--open` launches the local page automatically.

Ordinary commit subjects and diffs remain confirmed Git evidence. Conventional
commit classifications are marked inferred, while absent rationale and risk are
shown exactly as `not recorded`. OrbitCart-only Ask the Repo and Bug Origin
artifacts are not exposed for generic repositories.

The workflow is dogfooded on this repository: its M0-M4 commits render in
chronological order, shared files connect milestones, and the foundation-to-HEAD
context report is grounded in real changed files. See
[the M4.5 implementation brief](docs/M4.5_REAL_REPO_MODE.md).

## Quick start

Requirements: Python 3.11+ and Git. No third-party packages are required.

```bash
git clone https://github.com/ved-devAI/AI_Time_Machine.git
cd AI_Time_Machine
python3 scripts/create_orbitcart.py
python3 -m app.server
```

Open <http://127.0.0.1:8765>.

The local app reads the generated OrbitCart Git repository at request time. The
public demo is an API-free snapshot produced from that same repository during
deployment. Its timeline and Codex references are checked before publication,
and the UI labels hosted evidence as a verified Git snapshot rather than a live
model call.

## Quick test without rebuilding

Analyze the current Git worktree directly, or open it in Real Repo Mode:

```bash
python3 -m app.cli analyze .
python3 -m app.cli serve --open
```

These commands read the existing repository history and do not regenerate the
OrbitCart demo repository.

## Verify everything

Run the complete zero-dependency verification suite:

```bash
python3 scripts/verify.py
```

This regenerates OrbitCart, runs all application and repository tests, validates
both Codex artifacts, produces a deterministic grounding scorecard, and checks
the browser JavaScript and repository whitespace.

Individual commands:

```bash
python3 -m unittest discover -s tests -v
PYTHONPATH=.data/orbitcart python3 -m unittest discover -s .data/orbitcart/tests -v
python3 scripts/codex_artifact.py validate
python3 scripts/ask_repo_artifact.py validate
python3 scripts/evaluate_grounding.py
```

## How it works

1. `scripts/create_orbitcart.py` creates a genuine 12-commit demo repository.
2. `app/git_ingest.py` reads generic commit metadata, changed files, overlap
   history, and branch/range context using Git.
3. `scripts/codex_artifact.py` exports evidence and validates a strict,
   reproducible GPT-5.6-in-Codex artifact.
4. `app/analysis.py` verifies artifact provenance, evidence digest, event IDs,
   commit hashes, and file references before returning an investigation.
5. `app/ask_repo.py` serves three reference-validated, evidence-linked repository answers.
6. `app/repo_questions.py` produces and validates four deterministic answers
   for ordinary repositories.
7. `app/cli.py` selects a local repository for analysis, context, or serving.
8. `app/server.py` exposes the selected timeline and branch review while restricting reference-validated
   OrbitCart artifacts to OrbitCart.
9. `frontend/` renders the Developer Workspace, Ask the Repo, the timeline, and
   the Bug Origin Trace.

The default flow makes no paid runtime call. It replays the committed artifact
generated by GPT-5.6 Sol through ChatGPT-authenticated Codex. If the artifact is
missing or fails validation, the investigation remains runnable using an
explicitly labeled local evidence fallback.

## Reproduce the Codex artifact

```bash
python3 scripts/codex_artifact.py prepare
codex exec -m gpt-5.6-sol -s read-only \
  --output-schema artifacts/orbitcart/analysis.schema.json \
  -o .data/codex-run/analysis.json \
  "Read artifacts/orbitcart/analysis.prompt.md and perform that task."
python3 scripts/codex_artifact.py finalize .data/codex-run/analysis.json \
  --model gpt-5.6-sol
python3 scripts/codex_artifact.py validate
```

Ask the Repo uses the same workflow with `artifacts/orbitcart/ask-repo.prompt.md`,
`scripts/ask_repo_artifact.py`, and its own strict output schema. Both committed
artifacts are tied to the same OrbitCart evidence digest.

`codex exec` reuses ChatGPT-managed Codex authentication. The app does not need
an API key to replay the reference-validated result.

See [the analysis design](docs/ai-analysis.md) for grounding and fallback details
and [the evaluation guide](docs/EVALUATION.md) for the scorecard.

## Public deployment

```bash
python3 scripts/create_orbitcart.py
python3 scripts/build_public_demo.py
```

The build writes a static client and a minimal host worker to `dist/`. Pushes to
`main` run the full verification suite; production releases package the same
reference-validated build for the public host. No API key or paid runtime call is required.

## Release screenshots

- [Desktop product overview](docs/screenshots/ai-time-machine-desktop.png)
- [Bug Origin Trace](docs/screenshots/ai-time-machine-bug-origin-trace.png)
- [390 × 844 mobile trace](docs/screenshots/ai-time-machine-mobile-390x844.png)


## Detected evidence (automated analysis)

Indexed codebase: 39 recognized source files, 286 KB.
- CSS (language) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- OpenAI (technology) — claimed on Devpost, not found in the code
- AI coding agent: Codex — evidence: config files committed to the repository

## Codebase structure (from repository index)

### Files (50 of 50)

```
.env.example
.github/workflows/verify.yml
.gitignore
.openai/hosting.json
AGENTS.md
app/__init__.py
app/analysis.py
app/ask_repo.py
app/cli.py
app/git_ingest.py
app/repo_questions.py
app/server.py
artifacts/orbitcart/analysis.prompt.md
artifacts/orbitcart/analysis.schema.json
artifacts/orbitcart/ask-repo.codex.json
artifacts/orbitcart/ask-repo.prompt.md
artifacts/orbitcart/ask-repo.schema.json
artifacts/orbitcart/bug-origin.codex.json
artifacts/orbitcart/evaluation-report.json
artifacts/orbitcart/evidence.json
CONTEXT.md
docs/ai-analysis.md
docs/data-contract.md
docs/DECISIONS.md
docs/EVALUATION.md
docs/M4.5_REAL_REPO_MODE.md
docs/M5.md
docs/UPCOMING_DEVELOPER_MILESTONES.md
evaluations/orbitcart_grounding.json
frontend/app.js
frontend/index.html
frontend/runtime-config.js
frontend/styles.css
LICENSE
PRODUCT_CONTRACT.md
README.md
ROADMAP.md
scripts/ask_repo_artifact.py
scripts/build_public_demo.py
scripts/codex_artifact.py
scripts/create_orbitcart.py
scripts/evaluate_grounding.py
scripts/verify.py
tests/test_analysis.py
tests/test_ask_repo.py
tests/test_evaluation.py
tests/test_git_ingest.py
tests/test_public_demo.py
tests/test_real_repo_mode.py
tests/test_responsive_css.py
```

### Dependencies

No dependency index available.

### Recent commits (newest first)

- Polish README for submission
- Complete M5 trust integrity milestones
- Improve interface readability and scrolling
- Complete M4.6 developer workspace
- Define M4.5 real repository mode
- Complete M4 release handoff
- Configure production hosting
- Polish and package public demo
- Add grounding evaluation and judge verification
- Build evidence-grounded Ask the Repo
- Add validated GPT-5.6 Codex artifact
- Add durable project handoff workflow
- Build AI Time Machine evidence timeline

## Key source files (fetched from GitHub, selected and truncated for size)

### AGENTS.md

```markdown
# AI Time Machine repository instructions

## Start every task here

1. Read `CONTEXT.md` completely.
2. Check `git status --short --branch` and `git log -1 --oneline`.
3. Read the specific implementation files named by the current task in
   `CONTEXT.md`.
4. Preserve unrelated user changes.

## Product invariants

- AI Time Machine explains why a codebase evolved using observable repository
  evidence.
- Every causal claim must point to real event IDs, commits, or affected files.
- Clearly distinguish confirmed facts, inference, and missing evidence.
- The default demo must work without an OpenAI API key or paid runtime call.
- Never label fallback or deterministic output as live GPT-5.6 output.
- GPT-5.6 usage through Codex must be documented honestly as build-time analysis,
  implementation, review, and evaluation unless a live API call actually ran.
- Keep OrbitCart deterministic so the three-minute demo remains reliable.

## Verification

Run before committing a milestone:

```bash
python3 scripts/verify.py
# Equivalent individual checks:
python3 -m unittest discover -s tests -v
PYTHONPATH=.data/orbitcart python3 -m unittest discover -s .data/orbitcart/tests -v
python3 scripts/codex_artifact.py validate
python3 scripts/ask_repo_artifact.py validate
python3 scripts/evaluate_grounding.py
node --check frontend/app.js
git diff --check
```

Also verify the affected browser flow for UI changes.

## Handoff maintenance

After each major session, refresh the top snapshot in `CONTEXT.md` with:

- What changed
- What is verified
- What remains incomplete
- The exact next task
- Any new commands, constraints, or risks

Update `ROADMAP.md` milestone statuses and append material architecture choices
to `docs/DECISIONS.md`. Do not place secrets, tokens, API keys, or private key
material in any handoff file.

```

### PRODUCT_CONTRACT.md

```markdown
# AI Time Machine — Product Contract

## Demo promise

AI Time Machine analyzes real Git history and reconstructs an evidence-backed
timeline explaining why a codebase evolved. Its flagship experience traces a
bug back to the change that likely introduced it.

## Judge-facing proof

The first demo repository is OrbitCart, a small but genuine Git repository with
a deliberately authored engineering history. The app reads its commits and
diffs at runtime. Timeline cards are not hard-coded into the interface.

The headline investigation follows a stale-price bug caused by an earlier
checkout caching optimization. AI Time Machine will show the optimization, the
later failure, the rollback, and the eventual safe fix as a causal chain.

## MVP boundary

Included:

- Real Git ingestion
- Interactive chronological timeline
- Event details and affected files
- Evidence, certainty, and confidence labels
- Ask the Repo using GPT-5.6
- Bug Origin Trace

Deferred:

- GitHub OAuth and private repository access
- Team accounts and enterprise indexing
- Multiple source-control providers
- Autonomous code modification

## Evidence rules

Every claim must be attached to observable repository evidence. The interface
must distinguish confirmed facts from inferences. Missing evidence must never
be silently converted into certainty.

## Real Repo Mode developer proof

Real Repo Mode will add a local-only workflow for arbitrary Git repositories.
It will reuse the evidence and certainty rules above, keep OrbitCart as the
flagship demo, and prove genericity by analyzing AI Time Machine's own history.

Required scope is local repository selection, generic timeline ingestion,
browser serving, and branch or commit-range context. An opt-in
ChatGPT-authenticated Codex artifact may be added only after the evidence-only
workflow passes. GitHub OAuth, hosted private repositories, editor extensions,
team features, and autonomous modification remain deferred.

## Developer workspace and planned opt-in integrations

M4.6 exposes the existing branch context engine in the browser, makes local
startup one command, and adds adaptive deterministic questions for ordinary
repositories. These answers remain evidence-engine output and are never labeled
as GPT output. Browser requests may select Git revisions for review but cannot
change the repository path fixed at server startup.

Optional custom AI analysis is BYOK and local-server-only. A user may configure
their own Platform API key outside the browser process, but the public client
must never receive, persist, or transmit that key. The zero-key workflow remains
complete and is always the default.

Remote Git authentication remains separate from model authentication. The first
integration should reuse a developer's existing local Git or GitHub CLI login.
A future hosted connection should use a fine-grained, read-only GitHub App for
selected repositories rather than broad OAuth access. See
`docs/UPCOMING_DEVELOPER_MILESTONES.md`.

```

### app/cli.py

```python
"""Local developer workflow for analyzing and serving a Git repository."""

from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path
from typing import Any

from app.git_ingest import GitRepositoryError, read_change_context, read_timeline
from app.server import run_server


def _write_json(payload: Any, output: Path | None) -> None:
    content = json.dumps(payload, indent=2, ensure_ascii=False) + "\n"
    if output is None:
        print(content, end="")
        return
    output = output.expanduser().resolve()
    output.parent.mkdir(parents=True, exist_ok=True)
    output.write_text(content, encoding="utf-8")
    print(f"Wrote {output}")


def parse_args(argv: list[str] | None = None) -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        prog="python3 -m app.cli",
        description="Analyze local Git history without an API key.",
    )
    commands = parser.add_subparsers(dest="command", required=True)

    analyze = commands.add_parser("analyze", help="Print a normalized Git timeline")
    analyze.add_argument("repository", type=Path)
    analyze.add_argument("--branch", default="HEAD", help="Branch, tag, or commit to analyze")
    analyze.add_argument("--output", type=Path, help="Write JSON to this local path")

    serve = commands.add_parser("serve", help="Serve a repository in the browser UI")
    serve.add_argument("repository", type=Path, nargs="?", default=Path("."))
    serve.add_argument("--branch", default="HEAD", help="Branch, tag, or commit to serve")
    serve.add_argument("--host", default="127.0.0.1")
    serve.add_argument("--port", type=int, default=8765)
    serve.add_argument("--open", action="store_true", help="Open the local workspace in a browser")

    context = commands.add_parser("context", help="Report evidence for a commit range")
    context.add_argument("repository", type=Path)
    context.add_argument("--base", required=True, help="Base branch or commit")
    context.add_argument("--head", default="HEAD", help="Head branch or commit")
    context.add_argument("--recent-limit", type=int, default=5)
    context.add_argument("--output", type=Path, help="Write JSON to this local path")
    return parser.parse_args(argv)


def main(argv: list[str] | None = None) -> int:
    args = parse_args(argv)
    try:
        if args.command == "analyze":
            _write_json(read_timeline(args.repository, args.branch), args.output)
        elif args.command == "context":
            if args.recent_limit < 1:
                raise GitRepositoryError("--recent-limit must be at least 1.")
            _write_json(
                read_change_context(
                    args.repository,
                    args.base,
                    args.head,
                    args.recent_limit,
                ),
                args.output,
            )
        else:
            if not 1 <= args.port <= 65535:
                raise GitRepositoryError("--port must be between 1 and 65535.")
            run_server(args.repository, args.branch, args.host, args.port, args.open)
        return 0
    except (GitRepositoryError, OSError) as exc:
        print(f"error: {exc}", file=sys.stderr)
        return 2


if __name__ == "__main__":
    raise SystemExit(main())

```

### app/server.py

```python
"""Zero-dependency development server for the AI Time Machine vertical slice."""

from __future__ import annotations

import json
import mimetypes
import os
import threading
import webbrowser
from http import HTTPStatus
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from pathlib import Path
from urllib.parse import parse_qs, urlparse

from app.analysis import AnalysisError, analyze_bug_origin
from app.ask_repo import QUESTIONS, ask_repo
from app.git_ingest import GitRepositoryError, read_change_context, read_timeline
from app.repo_questions import QUESTIONS as REPO_QUESTIONS
from app.repo_questions import answer_question


ROOT = Path(__file__).resolve().parents[1]
FRONTEND = ROOT / "frontend"
ORBITCART = ROOT / ".data" / "orbitcart"
ANALYSIS_CACHE = ROOT / ".data" / "orbitcart-analysis.json"
CODEX_ARTIFACT = ROOT / "artifacts" / "orbitcart" / "bug-origin.codex.json"
ASK_REPO_ARTIFACT = ROOT / "artifacts" / "orbitcart" / "ask-repo.codex.json"


def load_local_env(path: Path) -> None:
    """Load simple KEY=VALUE entries without adding a package dependency."""

    if not path.exists():
        return
    for raw_line in path.read_text(encoding="utf-8").splitlines():
        line = raw_line.strip()
        if not line or line.startswith("#") or "=" not in line:
            continue
        key, value = line.split("=", 1)
        key = key.strip()
        value = value.strip().strip('"').strip("'")
        if key:
            os.environ.setdefault(key, value)


class Handler(BaseHTTPRequestHandler):
    repository = ORBITCART
    revision = "HEAD"
    orbitcart_features = True
    default_base = "HEAD~1"

    def _json(self, payload: object, status: HTTPStatus = HTTPStatus.OK) -> None:
        body = json.dumps(payload).encode("utf-8")
        self.send_response(status)
        self.send_header("Content-Type", "application/json; charset=utf-8")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def _file(self, path: Path) -> None:
        if not path.exists() or not path.is_file():
            self.send_error(HTTPStatus.NOT_FOUND)
            return
        body = path.read_bytes()
        content_type = mimetypes.guess_type(path.name)[0] or "application/octet-stream"
        self.send_response(HTTPStatus.OK)
        self.send_header("Content-Type", f"{content_type}; charset=utf-8")
        self.send_header("Content-Length", str(len(body)))
        self.end_headers()
        self.wfile.write(body)

    def _request_json(self) -> dict[str, object]:
        try:
            length = int(self.headers.get("Content-Length", "0"))
        except ValueError as exc:
            raise ValueError("Invalid request size.") from exc
        if length <= 0 or length > 4096:
            raise ValueError("Request body must be between 1 and 4096 bytes.")
        try:
            payload = json.loads(self.rfile.read(length).decode("utf-8"))
        except (UnicodeDecodeError, json.JSONDecodeError) as exc:
            raise ValueError("Request body must be valid JSON.") from exc
        if not isinstance(payload, dict):
            raise ValueError("Request body must be a JSON object.")
        return payload

    def do_GET(self) -> None:  # noqa: N802 - BaseHTTPRequestHandler API
        parsed = urlparse(self.path)
        path = parsed.path
        if path == "/api/health":
            self._json({"status": "ok", "service": "ai-time-machine"})
            return
        if path in {"/api/timeline", "/api/projects/orbitcart/timeline"}:
            if not self.repository.exists():
                self._json(
                    {"error": "OrbitCart has not been generated. Run scripts/create_orbitcart.py."},
                    HTTPStatus.SERVICE_UNAVAILABLE,
                )
                return
            self._json(read_timeline(self.repository, self.revision))
            return
        if path == "/api/context":
            if self.orbitcart_features:
                self._json(
                    {"error": "Branch review is available in Developer Workspace mode."},
                    HTTPStatus.NOT_FOUND,
                )
                return
            query = parse_qs(parsed.query, keep_blank_values=True)
            base = query.get("base", [self.default_base])[0]
            head = query.get("head", [self.revision])[0]
            try:
                self._json(read_change_context(self.repository, base, head))
            except GitRepositoryError as exc:
                self._json({"error": str(exc)}, HTTPStatus.BAD_REQUEST)
            return
        if path == "/api/questions":
            if self.orbitcart_features:
                self._json(
                    {"error": "Adaptive questions are available in Developer Workspace mode."},
                    HTTPStatus.NOT_FOUND,
                )
                return
            self._json(
                {
                    "questions": REPO_QUESTIONS,
                    "source": "local-evidence-engine",
                    "base": self.default_base,
                    "head": self.revision,
                }
            )
            return
        if path == "/api/projects/orbitcart/questions":
            if not self.orbitcart_features:
                self._json(
                    {"error": "Ask the Repo is available only for the validated OrbitCart demo."},
                    HTTPStatus.NOT_FOUND,
                )
                return
            self._json({"questions": QUESTIONS})
            return
        if path == "/":
            self._file(FRONTEND / "index.html")
            return
        requested = (FRONTEND / path.lstrip("/")).resolve()
        if FRONTEND.resolve() not in requested.parents:
            self.send_error(HTTPStatus.FORBIDDEN)
            return
        self._file(requested)

    def do_POST(self) -> None:  # noqa: N802 - BaseHTTPRequestHandler API
        path = urlparse(self.path).path
        
[truncated — 4458 more characters]
```

### frontend/app.js

```javascript
const runtime = window.AI_TIME_MACHINE_RUNTIME || { mode: "local" };
const state = {
  events: [],
  selectedId: null,
  filter: "all",
  investigation: null,
  answers: {},
  questions: [],
  contextBase: null,
  contextHead: null,
  isOrbitCart: true,
  traceReturnFocus: null,
  askReturnFocus: null,
};

const timeline = document.querySelector("#timeline");
const detail = document.querySelector("#detail-panel");

document.querySelector("#runtime-label").textContent = runtime.mode === "snapshot"
  ? "Git snapshot verified"
  : "Git evidence verified";

async function requestJson(apiPath, snapshotPath, options = undefined) {
  const response = runtime.mode === "snapshot"
    ? await fetch(snapshotPath)
    : await fetch(apiPath, options);
  const payload = await response.json();
  if (!response.ok) throw new Error(payload.error || `Request failed (${response.status})`);
  return payload;
}

const icons = {
  feature: "✦",
  bug: "!",
  fix: "✓",
  refactor: "⌁",
  performance: "↗",
  rollback: "↶",
  test: "◆",
  change: "•",
};

const labels = {
  feature: "Feature",
  bug: "Incident",
  fix: "Fix",
  refactor: "Architecture",
  performance: "Performance",
  rollback: "Rollback",
  test: "Verification",
  change: "Change",
};

function eventTypeLabel(event) {
  const label = labels[event.type] || "Change";
  return !state.isOrbitCart && event.type_certainty === "inferred"
    ? `${label} · inferred`
    : label;
}

function eventEvidenceLabel(event) {
  return state.isOrbitCart
    ? `${Math.round(event.confidence * 100)}% confidence`
    : "Commit + diff verified";
}

function eventCertaintyLabel(event) {
  return state.isOrbitCart ? event.certainty : "Git verified";
}

function escapeHtml(value) {
  return String(value)
    .replaceAll("&", "&amp;")
    .replaceAll("<", "&lt;")
    .replaceAll(">", "&gt;")
    .replaceAll('"', "&quot;")
    .replaceAll("'", "&#039;");
}

function formatDate(value) {
  return new Intl.DateTimeFormat("en", { day: "2-digit", month: "short", year: "numeric" }).format(new Date(value));
}

function visibleEvents() {
  if (state.filter === "all") return state.events;
  if (state.filter === "fix") return state.events.filter((event) => ["fix", "rollback", "test"].includes(event.type));
  return state.events.filter((event) => event.type === state.filter);
}

function renderTimeline() {
  const events = visibleEvents();
  document.querySelector("#event-count").textContent = `${events.length} EVENT${events.length === 1 ? "" : "S"}`;
  if (!events.length) {
    timeline.innerHTML = '<div class="loading-state"><p>No events match this view.</p></div>';
    return;
  }
  timeline.innerHTML = events
    .map(
      (event) => `
        <button class="event-card ${event.type} ${event.id === state.selectedId ? "selected" : ""}" data-event-id="${escapeHtml(event.id)}" aria-pressed="${event.id === state.selectedId}">
          <span class="event-node">${icons[event.type] || "•"}</span>
          <span class="event-content">
            <span class="event-meta"><span class="type-badge">${eventTypeLabel(event)}</span><time>${formatDate(event.occurred_at)}</time></span>
            <strong>${escapeHtml(event.title)}</strong>
            <span class="event-summary">${escapeHtml(event.summary)}</span>
            <span class="event-footer"><code>${escapeHtml(event.short_hash)}</code><span>${event.files.length} file${event.files.length === 1 ? "" : "s"}</span><span class="certainty"><i></i>${escapeHtml(eventCertaintyLabel(event))}</span></span>
          </span>
        </button>`,
    )
    .join("");

  timeline.querySelectorAll(".event-card").forEach((card) => {
    card.addEventListener("click", () => selectEvent(card.dataset.eventId));
  });
}

function selectEvent(id) {
  state.selectedId = id;
  const event = state.events.find((item) => item.id === id);
  if (!event) return;
  renderTimeline();
  renderDetail(event);
}

function showAllEvents() {
  state.filter = "all";
  document.querySelectorAll(".filter").forEach((filter) => {
    const isAll = filter.dataset.filter === "all";
    filter.classList.toggle("active", isAll);
    filter.setAttribute("aria-pressed", String(isAll));
  });
}

function openEvidenceEvent(eventId) {
  showAllEvents();
  selectEvent(eventId);
  document.querySelector(".workspace").scrollIntoView({ behavior: "smooth", block: "start" });
}

function renderDetail(event) {
  const traceable = state.isOrbitCart && event.title.toLowerCase().includes("stale checkout");
  const related = event.related_event_ids
    .map((id) => state.events.find((item) => item.id === id))
    .filter(Boolean);
  detail.innerHTML = `
    <header class="detail-header ${event.type}">
      <div class="detail-title-row">
        <span class="large-icon">${icons[event.type] || "•"}</span>
        <div><span class="type-badge">${eventTypeLabel(event)}</span><h2>${escapeHtml(event.title)}</h2></div>
      </div>
      <div class="detail-meta"><time>${formatDate(event.occurred_at)}</time><span>by ${escapeHtml(event.author)}</span><code>${escapeHtml(event.short_hash)}</code></div>
    </header>
    ${traceable ? `
      <section class="trace-cta">
        <div><span class="trace-kicker">✦ CAUSAL INVESTIGATION</span><strong>Find where this bug really began</strong><p>Replay a reference-validated Codex analysis linked to Git evidence.</p></div>
        <button class="trace-button" id="trace-origin-button"><span>↶</span> Trace bug origin</button>
      </section>` : ""}
    <div class="detail-body">
      <section class="insight primary-insight">
        <p class="section-label">WHAT CHANGED</p>
        <p>${escapeHtml(event.summary)}</p>
      </section>
      <section class="insight why-insight">
        <p class="section-label">WHY IT MATTERED</p>
        <p>${escapeHtml(event.why)}</p>
      </section>
      <section>
        <div class="section-heading"><p class="section-label">EVIDENCE</p><span class="confidence"><i></i>${escapeHtml(eventEvidenceLabel(event))}</span></div>
  
[truncated — 20880 more characters]
```

### app/__init__.py

```python
"""AI Time Machine backend package."""


```

### frontend/runtime-config.js

```javascript
window.AI_TIME_MACHINE_RUNTIME = Object.freeze({ mode: "local" });

```

### tests/test_evaluation.py

```python
from __future__ import annotations

import unittest

from scripts.evaluate_grounding import run_evaluation


class GroundingEvaluationTests(unittest.TestCase):
    def test_committed_artifacts_achieve_full_grounding_score(self) -> None:
        report = run_evaluation()
        self.assertEqual(report["status"], "pass")
        self.assertEqual(report["score"], 100.0)
        self.assertEqual(report["passed"], report["total"])


if __name__ == "__main__":
    unittest.main()

```

### tests/test_git_ingest.py

```python
from __future__ import annotations

import subprocess
import sys
import unittest
from pathlib import Path

from app.git_ingest import read_timeline


ROOT = Path(__file__).resolve().parents[1]
ORBITCART = ROOT / ".data" / "orbitcart"


class GitIngestTests(unittest.TestCase):
    @classmethod
    def setUpClass(cls) -> None:
        if not ORBITCART.exists():
            subprocess.run([sys.executable, "scripts/create_orbitcart.py"], cwd=ROOT, check=True)

    def test_reads_all_curated_commits(self) -> None:
        timeline = read_timeline(ORBITCART)
        self.assertEqual(timeline["stats"]["commits"], 12)
        self.assertEqual(len(timeline["events"]), 12)

    def test_stale_price_incident_has_git_evidence(self) -> None:
        events = read_timeline(ORBITCART)["events"]
        incident = next(event for event in events if "stale checkout" in event["title"].lower())
        self.assertEqual(incident["type"], "bug")
        self.assertEqual(incident["certainty"], "confirmed")
        self.assertTrue(any(item["path"] == "history/issues/OC-52.md" for item in incident["files"]))

    def test_file_overlap_builds_history_connections(self) -> None:
        events = read_timeline(ORBITCART)["events"]
        cache_fix = next(event for event in events if "catalog version" in event["title"].lower())
        self.assertGreaterEqual(len(cache_fix["related_event_ids"]), 1)


if __name__ == "__main__":
    unittest.main()


```

### scripts/verify.py

```python
#!/usr/bin/env python3
"""Run the complete judge-facing verification workflow with no extra packages."""

from __future__ import annotations

import subprocess
import sys
from pathlib import Path


ROOT = Path(__file__).resolve().parents[1]

COMMANDS = [
    ("Generate deterministic OrbitCart history", [sys.executable, "scripts/create_orbitcart.py"]),
    ("Run application tests", [sys.executable, "-m", "unittest", "discover", "-s", "tests", "-v"]),
    (
        "Run OrbitCart regression test",
        [sys.executable, "-m", "unittest", "discover", "-s", ".data/orbitcart/tests", "-v"],
    ),
    ("Validate Bug Origin artifact", [sys.executable, "scripts/codex_artifact.py", "validate"]),
    ("Validate Ask the Repo artifact", [sys.executable, "scripts/ask_repo_artifact.py", "validate"]),
    ("Build verified public demo", [sys.executable, "scripts/build_public_demo.py"]),
    (
        "Run grounding scorecard",
        [
            sys.executable,
            "scripts/evaluate_grounding.py",
            "--write",
            "artifacts/orbitcart/evaluation-report.json",
        ],
    ),
    ("Check browser JavaScript", ["node", "--check", "frontend/app.js"]),
    ("Check repository whitespace", ["git", "diff", "--check"]),
]


def main() -> None:
    print("AI Time Machine — judge verification\n")
    for index, (label, command) in enumerate(COMMANDS, start=1):
        print(f"[{index}/{len(COMMANDS)}] {label}", flush=True)
        environment = None
        if label == "Run OrbitCart regression test":
            environment = {"PYTHONPATH": str(ROOT / ".data" / "orbitcart")}
        subprocess.run(command, cwd=ROOT, env=environment, check=True)
        print()
    print("Verification complete: all checks passed.")


if __name__ == "__main__":
    main()

```

[28 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]