-
Notifications
You must be signed in to change notification settings - Fork 0
docs: bootstrap learning interoperability contracts #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
seonghobae
wants to merge
39
commits into
develop
Choose a base branch
from
agent/bootstrap-learning-contracts
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+819
−1
Open
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 d832628
docs: add standards traceability baseline
seonghobae 5d93593
feat: add learning event envelope schema
seonghobae 353a39a
docs: add agent development rules
seonghobae a14077d
docs: add initial changelog
seonghobae 24f8979
docs: add contract authority ADR
seonghobae b827ba7
docs: add development context
seonghobae 8bbfee6
docs: define learning contracts repository
seonghobae db726fa
ci: validate learning contracts bootstrap
seonghobae 61e621a
docs: accept learning contract authority ADR
seonghobae 7c71b91
docs: make learning standards traceability explicit
seonghobae edac706
feat: version learning event schema identity
seonghobae 4cd9555
test: enforce versioned learning schema contract
seonghobae de6146e
refactor: retire unversioned learning event schema path
seonghobae eaccf36
docs: add canonical DeepWiki badge
seonghobae 5c5f781
fix: harden learning event timestamp contract
seonghobae 3503597
fix: validate schemas and timestamp edge cases
seonghobae f1adff9
docs: add commercialization gap baseline
seonghobae 4b7495a
docs: separate standards adoption from conformance evidence
seonghobae 425753b
docs: distinguish standards adoption from conformance evidence
seonghobae 946d718
fix: enforce timestamp format assertions in schema tests
seonghobae 51876a2
docs: align commercialization status with exact-head evidence
seonghobae 7a3c4e7
docs: keep live CI state out of contracts baseline
seonghobae f44ce2c
fix: pin RFC3339 format checker dependency
seonghobae ed6e371
test: prove RFC3339 checker is active
seonghobae e6457a3
fix: use immutable logical schema identity
seonghobae a13cc64
ci: bind schema id to immutable version identity
seonghobae 7f044c1
docs: grant Apache-2.0 source license
seonghobae 1062d45
docs: pin cmi5 Quartz normative source
seonghobae e91c9bc
docs: reconcile schema and timestamp gap evidence
seonghobae 05a383e
docs: record contract traceability corrections
seonghobae 2fe6057
docs: add Pages-ready public landing source
seonghobae 8807894
ci: pin quality runner to ubuntu 24.04
seonghobae 031693d
docs: record explicit quality runner
seonghobae 6a299fa
docs: record runner admission repair
seonghobae cebd8e9
ci: run quality on stacked pull requests
seonghobae 0f37d0b
docs: record stacked quality coverage
seonghobae 6556122
docs: close stacked quality trigger gap
seonghobae 18ae682
docs: define product and technical requirements
seonghobae File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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' | ||
| - 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() | ||
|
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) | ||
|
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
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
|
|
||
| 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") | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.