Skip to content

Latest commit

 

History

History
148 lines (103 loc) · 4.26 KB

File metadata and controls

148 lines (103 loc) · 4.26 KB

Question Schema

Schema is provisional. Spikes are expected to surface friction with this format. If a convention does not work for your approach, document why in your spike writeup. The schema will be revised before the integration phase.

Directory structure

Each question is a folder under questions/ named by its question ID.

questions/<question-id>/
  index.md         — frontmatter metadata + markdown problem statement
  starter.<ext>    — starter code shown to the student
  solution.<ext>   — reference solution; must pass the test file
  tests.<ext>      — test suite executed against the student's submission

<ext> is .py for Python and .java for Java.

index.md frontmatter

---
id: string          # matches the folder name exactly
title: string       # display title shown to the student
type: code          # literal string "code"
language: python | java
tags: [string, ...]  # topic tags, e.g. ["recursion", "strings"]
entry_point: string  # the function or class name the student implements
---

The markdown body of index.md is the problem statement shown to the student. Write it as you would a problem description on an assignment sheet.

starter.<ext>

Starter code shown to the student in the editor. Should include:

  • Any required imports
  • The function or class signature matching entry_point
  • A TODO comment body or pass/stub return

The student replaces the stub with their implementation.

solution.<ext>

The reference solution. Must pass tests.<ext> without modification. Not shown to the student.

tests.<ext>

The test file executed by the spike runner against the student's submission.

Conventions

Python. The test file imports the submission as solution and calls solution.<entry_point>:

import solution
result = solution.add(1, 2)

The submission file is always named solution.py at runtime, regardless of what the student originally named it.

Java. The test file references the student's class directly by the entry_point name. The submission class must be in the same package (default package) as the test file.

Output protocol

The runner executes the test file and determines pass/fail from two signals:

  1. Exit code. 0 = all tests passed. Non-zero = at least one failure or a runtime error.
  2. Structured stdout. The test file must print a single JSON line to stdout as its last line of output:
{"passed": 3, "failed": 1, "failures": [{"test": "test_name", "message": "expected X got Y"}]}

Both signals are expected. A runner that only checks exit code is incomplete. A runner that only checks stdout is also incomplete — use both.

Spike authors: if this output protocol is impractical for your execution environment, document the specific friction and propose an alternative in your writeup.


Worked example — questions/add-two-numbers/

A trivial Python question to illustrate all four files.

index.md

---
id: add-two-numbers
title: Add Two Numbers
type: code
language: python
tags: ["arithmetic", "functions"]
entry_point: add
---

Implement a function `add(a, b)` that returns the sum of two integers `a` and `b`.

**Example**

- `add(1, 2)``3`
- `add(-1, 5)``4`
- `add(0, 0)``0`

starter.py

def add(a: int, b: int) -> int:
    # TODO: implement this function
    pass

solution.py

def add(a: int, b: int) -> int:
    return a + b

tests.py

The harness is hand-rolled rather than using unittest or pytest so that the output protocol is explicit and not dependent on a test framework's output format. Spike authors can replace it once they know what their runner can parse.

import json
import solution

results = {"passed": 0, "failed": 0, "failures": []}

def run(name, got, expected):
    if got == expected:
        results["passed"] += 1
    else:
        results["failed"] += 1
        results["failures"].append({
            "test": name,
            "message": f"expected {expected} got {got}",
        })

run("test_positive",  solution.add(1, 2),   3)
run("test_negative",  solution.add(-1, 5),  4)
run("test_zeros",     solution.add(0, 0),   0)
run("test_large",     solution.add(100, 200), 300)

print(json.dumps(results))
exit(results["failed"])