Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
022d3b3
docs: define interoperability boundaries
seonghobae Aug 19, 2026
d832628
docs: add standards traceability baseline
seonghobae Aug 19, 2026
5d93593
feat: add learning event envelope schema
seonghobae Aug 19, 2026
353a39a
docs: add agent development rules
seonghobae Aug 19, 2026
a14077d
docs: add initial changelog
seonghobae Aug 19, 2026
24f8979
docs: add contract authority ADR
seonghobae Aug 19, 2026
b827ba7
docs: add development context
seonghobae Aug 19, 2026
8bbfee6
docs: define learning contracts repository
seonghobae Aug 19, 2026
db726fa
ci: validate learning contracts bootstrap
seonghobae Aug 19, 2026
61e621a
docs: accept learning contract authority ADR
seonghobae Aug 19, 2026
7c71b91
docs: make learning standards traceability explicit
seonghobae Aug 19, 2026
edac706
feat: version learning event schema identity
seonghobae Aug 19, 2026
4cd9555
test: enforce versioned learning schema contract
seonghobae Aug 19, 2026
de6146e
refactor: retire unversioned learning event schema path
seonghobae Aug 19, 2026
eaccf36
docs: add canonical DeepWiki badge
seonghobae Sep 1, 2026
5c5f781
fix: harden learning event timestamp contract
seonghobae Sep 1, 2026
3503597
fix: validate schemas and timestamp edge cases
seonghobae Sep 1, 2026
f1adff9
docs: add commercialization gap baseline
seonghobae Sep 1, 2026
4b7495a
docs: separate standards adoption from conformance evidence
seonghobae Sep 1, 2026
425753b
docs: distinguish standards adoption from conformance evidence
seonghobae Sep 1, 2026
946d718
fix: enforce timestamp format assertions in schema tests
seonghobae Sep 1, 2026
51876a2
docs: align commercialization status with exact-head evidence
seonghobae Sep 1, 2026
7a3c4e7
docs: keep live CI state out of contracts baseline
seonghobae Sep 1, 2026
f44ce2c
fix: pin RFC3339 format checker dependency
seonghobae Sep 1, 2026
ed6e371
test: prove RFC3339 checker is active
seonghobae Sep 1, 2026
e6457a3
fix: use immutable logical schema identity
seonghobae Sep 1, 2026
a13cc64
ci: bind schema id to immutable version identity
seonghobae Sep 1, 2026
7f044c1
docs: grant Apache-2.0 source license
seonghobae Sep 1, 2026
1062d45
docs: pin cmi5 Quartz normative source
seonghobae Sep 1, 2026
e91c9bc
docs: reconcile schema and timestamp gap evidence
seonghobae Sep 1, 2026
05a383e
docs: record contract traceability corrections
seonghobae Sep 1, 2026
2fe6057
docs: add Pages-ready public landing source
seonghobae Sep 1, 2026
8807894
ci: pin quality runner to ubuntu 24.04
seonghobae Sep 1, 2026
031693d
docs: record explicit quality runner
seonghobae Sep 1, 2026
6a299fa
docs: record runner admission repair
seonghobae Sep 1, 2026
cebd8e9
ci: run quality on stacked pull requests
seonghobae Sep 1, 2026
0f37d0b
docs: record stacked quality coverage
seonghobae Sep 1, 2026
6556122
docs: close stacked quality trigger gap
seonghobae Sep 1, 2026
18ae682
docs: define product and technical requirements
seonghobae Sep 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 180 additions & 0 deletions .github/workflows/quality.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
name: Learning Contracts Quality

on:
pull_request: {}
push:
branches: [develop, main]

permissions:
contents: read

concurrency:
group: learning-contracts-quality-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
validate:
# Live exact-head evidence showed ubuntu-latest remaining unassigned with no
# executed steps. The explicit Ubuntu 24.04 image is already proven usable
# by the sibling Learning Content Studio quality lane.
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- name: Checkout exact revision
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- name: Install pinned schema validator
run: python3 -m pip install --disable-pip-version-check --no-input 'jsonschema==4.26.0' 'rfc3339-validator==0.1.4'
Comment thread
seonghobae marked this conversation as resolved.
- name: Validate documentation and schemas
shell: python3 {0}
run: |
import json
import re
from datetime import datetime
from pathlib import Path

from jsonschema import Draft202012Validator, FormatChecker
from jsonschema.exceptions import SchemaError

schema_path = Path("schemas/v1/learning-event.schema.json")
required = [
Path("README.md"),
Path("AGENTS.md"),
Path("CLAUDE.md"),
Path("CHANGELOG.md"),
Path("docs/PRD.md"),
Path("docs/TRD.md"),
Path("docs/ARCHITECTURE.md"),
Path("docs/adr/0001-contract-authority-boundary.md"),
Path("docs/doctoring/STANDARD_TRACEABILITY.md"),
Path("docs/product-technical-gap-baseline.md"),
schema_path,
]
missing = [str(path) for path in required if not path.is_file()]
if missing:
raise SystemExit(f"missing required bootstrap files: {missing}")

schemas = {}
for path in Path("schemas").rglob("*.json"):
with path.open(encoding="utf-8") as handle:
value = json.load(handle)
try:
Draft202012Validator.check_schema(value)
except SchemaError as exc:
raise SystemExit(f"invalid Draft 2020-12 schema in {path}: {exc.message}") from exc
schemas[path] = value

# Prove the validator is checking schema semantics rather than JSON syntax alone.
try:
Draft202012Validator.check_schema({"$schema": "https://json-schema.org/draft/2020-12/schema", "type": 7})
except SchemaError:
pass
else:
raise SystemExit("schema validator accepted an invalid type keyword value")

schema = schemas[schema_path]
if schema.get("$schema") != "https://json-schema.org/draft/2020-12/schema":
raise SystemExit("learning event schema must use JSON Schema Draft 2020-12")

version = schema.get("x-cwl-schema-version", "")
version_match = re.fullmatch(r"(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)", version)
if not version_match:
raise SystemExit("learning event schema must declare a canonical semantic version")
path_major = schema_path.parent.name
if path_major != f"v{version_match.group(1)}":
raise SystemExit(
f"schema major version {version_match.group(1)} must match path segment {path_major!r}"
)

# `$id` is a canonical logical identifier, not a mutable branch URL or a
# claim that an unreleased schema has already been published. Its semantic
# version therefore determines an immutable identity before the first release.
expected_id = (
"urn:contextualwisdomlab:learning-interoperability-contracts:"
f"learning-event:{version}"
)
if schema.get("$id") != expected_id:
raise SystemExit("learning event schema $id must match the immutable version-derived identity")

def parse_contract_timestamp(candidate: str) -> datetime:
normalized = candidate
if len(normalized) > 10 and normalized[10] == "t":
normalized = normalized[:10] + "T" + normalized[11:]
if normalized.endswith(("Z", "z")):
normalized = normalized[:-1] + "+00:00"
return datetime.fromisoformat(normalized)

valid_timestamps = (
"2026-08-19T14:00:00Z",
"2026-08-19t14:00:00z",
"2024-02-29T23:59:59+14:00",
"2026-01-01T00:00:00-05:30",
"2026-01-01T00:00:00.123456Z",
)
invalid_timestamps = (
"2026-08-19",
"not-a-date",
"2026-08-19T14:00:00",
"2026-02-29T14:00:00Z",
"2026-13-01T14:00:00Z",
"2026-04-31T14:00:00Z",
"2026-01-01T24:00:00Z",
"2026-01-01T14:60:00Z",
"2026-01-01T14:00:60Z",
"2026-01-01T14:00:00+24:00",
"2026-01-01T14:00:00+14:60",
)
invalid_calendar_timestamps = (
"2026-02-29T14:00:00Z",
"2026-04-31T14:00:00Z",
)

format_checker = FormatChecker()
Comment thread
seonghobae marked this conversation as resolved.
if format_checker.conforms("2026-02-29T14:00:00Z", "date-time"):
raise SystemExit("date-time format checker is inactive or accepts an impossible calendar date")

for field_name in ("occurred_at", "recorded_at"):
field = schema["properties"][field_name]
if field.get("format") != "date-time" or not field.get("pattern"):
raise SystemExit(f"{field_name} must require date-time format and a syntax pattern")

# Draft 2020-12's default metaschema treats format as annotation. The
# contract gate therefore opts into executable format checking and
# combines it with the committed lexical pattern.
field_validator = Draft202012Validator(field, format_checker=format_checker)
Comment thread
coderabbitai[bot] marked this conversation as resolved.

for candidate in valid_timestamps:
errors = list(field_validator.iter_errors(candidate))
if errors:
raise SystemExit(
f"{field_name} schema rejects valid contract timestamp {candidate}: "
+ "; ".join(error.message for error in errors)
)
try:
parse_contract_timestamp(candidate)
except ValueError as exc:
raise SystemExit(f"{field_name} parser rejects valid timestamp: {candidate}") from exc

for candidate in invalid_timestamps:
errors = list(field_validator.iter_errors(candidate))
if not errors:
raise SystemExit(f"{field_name} schema accepts invalid timestamp: {candidate}")

for candidate in invalid_calendar_timestamps:
try:
parse_contract_timestamp(candidate)
except ValueError:
pass
else:
raise SystemExit(f"{field_name} parser accepts impossible calendar date: {candidate}")
Comment on lines +138 to +171

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Envelope fixtures remain release work

Quality checks identity and timestamps but lacks complete valid and invalid envelope fixtures. Documentation keeps this candidate unreleased until that evidence exists.

Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.


forbidden = ("TODO: replace", "TBD: replace", "PLACEHOLDER_REPLACE")
for path in required:
text = path.read_text(encoding="utf-8")
for marker in forbidden:
if marker in text:
raise SystemExit(f"unresolved bootstrap marker {marker!r} in {path}")

print("learning interoperability bootstrap contract validation passed")
10 changes: 10 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Agent development rules

- Preserve repository responsibility: contracts only, no application state or product-specific database ownership.
- Pin every standards adoption decision to a precise revision and authoritative source. Adoption is a product decision, not conformance evidence.
- Pin every implementation/conformance claim to the precise normative requirement, implementation location, executable fixture/test path, and exact-head CI evidence. Record absent evidence explicitly rather than inferring conformance from adoption or documentation.
- Maintain backward-compatible contracts where declared; incompatible changes require a new version.
- Do not silently translate historical learning records between xAPI versions.
- Generated SDKs must be reproducible from committed schemas.
- Production code introduced here requires 100% statement and branch coverage plus complete public API documentation.
- Database object naming rules are not applicable because this repository must not own a runtime database.
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changelog

## Unreleased

### Added

- Initial learning interoperability authority boundaries.
- Standards traceability baseline for xAPI, cmi5, LTI, QTI, CASE, Open Badges, CLR, and accessibility.
- Versioned learning-domain event envelope schema with an immutable semantic-version-derived logical URN.
- Repository agent development rules.
- Product requirements defining customer/integrator jobs, contract support gates, non-goals and release outcomes.
- Technical requirements defining the artifact-only bounded context, invariants, validation, release, security and consumer ACL requirements.

### Changed

- Pinned the adopted cmi5 Quartz normative source to the official immutable Quartz release commit instead of the mutable development branch.
- Reconciled the commercialization baseline so the immutable schema identity is distinguished from the still-missing protected release artifact, and portable timestamp conformance remains explicitly blocked until consumer format-assertion fixtures are executable across supported runtimes.
- Pinned the repository quality job to `ubuntu-24.04` after the live exact-head `ubuntu-latest` job remained unassigned with no executed steps; no validation, security, review, or release gate was weakened.
- Broadened repository Quality from only `develop`/`main` pull-request bases to every pull request so stacked feature PRs receive the same repository-local exact-head validation rather than silently skipping it.
- Repository Quality now requires PRD and TRD presence so foundational product/technical contracts cannot regress silently.
3 changes: 3 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Development context

Follow `AGENTS.md` and the organization-level engineering policy. This repository defines shared learning interoperability contracts only. Keep runtime application state and product-specific persistence in the owning repositories.
Loading
Loading