feat: DGR-018 canonical Ralph metadata schema
This commit is contained in:
204
.scratch/distributed-gguf-runtime/evidence/DGR-018/README.md
Normal file
204
.scratch/distributed-gguf-runtime/evidence/DGR-018/README.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# DGR-018 evidence — canonical Ralph and Gitea metadata schema
|
||||
|
||||
**Completed:** 2026-07-16
|
||||
**Branch:** `ralph/distributed-gguf-runtime`
|
||||
**Authority:** `.scratch/distributed-gguf-runtime/prd.json`
|
||||
**Dependency:** DGR-017 (`evidence/DGR-017/README.md`) — cleaned backlog reconciled to `origin/master`; no old pass state transferred.
|
||||
|
||||
## Objective
|
||||
|
||||
Make `prd.json` the validated source from which Markdown (and, later, Gitea) issues
|
||||
can be generated losslessly, per
|
||||
`.scratch/distributed-gguf-runtime/issues/018-define-canonical-ralph-and-gitea-metadata-schema.md`.
|
||||
|
||||
## Pre-existing state found (not caused by this story)
|
||||
|
||||
Before any change in this session, `git status` showed `.scratch/distributed-gguf-runtime/prd.json`
|
||||
already modified in the working tree relative to `HEAD` (commit `369b207`), with no corresponding
|
||||
progress-log entry. Diffing against `HEAD` showed the working copy had **dropped** prd.json's
|
||||
top-level `sourceOfTruth`, `qualityGates`, `metadataSchema`, `milestones`, and `supersededStories`
|
||||
objects, while `userStories` itself was byte-identical to `HEAD`. This looked like an abandoned,
|
||||
uncommitted partial edit from a prior session, not intentional current work — those fields are
|
||||
exactly the schema/quality-gate/audit-provenance content this story depends on, and their loss
|
||||
wasn't explained by any acceptance criterion. They were restored (see "Changes" below) rather than
|
||||
silently accepted or discarded, per the instruction to investigate unexplained working-tree state
|
||||
before building on top of it.
|
||||
|
||||
## Changes
|
||||
|
||||
### `scripts/ralph_prd_schema.py` (new)
|
||||
|
||||
Single module providing:
|
||||
|
||||
- **Parse:** `load_prd(path)` — JSON load with clear `PrdValidationError`s for missing file /
|
||||
invalid JSON / non-object document.
|
||||
- **Canonical schema registry:** `STORY_FIELDS` (name → required/type), `EXECUTION_MODES`,
|
||||
`EVIDENCE_CLASSES`, `HARDWARE_FLAGS`, `UPSTREAM_FLAGS`, `TRIAGE_VALUES`. Covers every field named
|
||||
in the acceptance criteria: stable `id`/`title`, `labels`, `milestone`, derived `type`
|
||||
(`derive_type`), `dependsOn`, derived `blocks`, `triage`, `evidenceClass`, and
|
||||
`hardware`/`model`/`upstream` flags.
|
||||
- **Structural validation:** `validate_schema(data)` — required fields, types, enum membership,
|
||||
ID convention, `type:`/`priority:` label cardinality, non-empty `acceptanceCriteria`.
|
||||
- **Semantic validation:** `validate_semantics(data)` — unique IDs, unique titles, `dependsOn`
|
||||
resolves to known stories (no self-dependency), dependency graph is acyclic (with a reported
|
||||
cycle path on failure), `blocks` matches the dependency graph exactly (sorted set equality, not
|
||||
superset), and `evidencePath` matches the per-story convention.
|
||||
- **Fresh vs. in-progress backlog:** `validate_fresh_backlog(data)` additionally requires every
|
||||
story to start `passes: false` (for a backlog that hasn't started execution yet);
|
||||
`validate_backlog(data)` is the composed check for a real, in-flight backlog where some stories
|
||||
have legitimately completed.
|
||||
- **Self-consistency check:** `validate_metadata_schema_consistency(data)` — when prd.json declares
|
||||
its own `metadataSchema`/`qualityGates` (as this one now does), verifies that self-documentation
|
||||
hasn't drifted from what the validator actually enforces (enum sets, required/optional field
|
||||
lists, presence of `qualityGates` and `generatedArtifactDisclaimer`). This is a no-op for minimal
|
||||
fixture PRDs that don't carry that documentation.
|
||||
- **Generation (one-directional, prd.json → artifact):** `render_issue_markdown(story, data)`
|
||||
renders the exact Markdown convention already used by
|
||||
`.scratch/distributed-gguf-runtime/issues/*.md`, sourcing the "Shared quality gates" bullets from
|
||||
`data["qualityGates"]` and the leading disclaimer from
|
||||
`data["metadataSchema"]["generatedArtifactDisclaimer"]` (falling back to a module default only
|
||||
when `data` omits them) — not from a duplicated Python string literal.
|
||||
`to_gitea_issue_payload(story, data)` wraps the same body into a Gitea create-issue-shaped payload
|
||||
(`title`, `body`, `labels`, `milestone`).
|
||||
- **Authority guard:** `check_generated_markdown_authority(text, disclaimer=...)` rejects generated
|
||||
Markdown that's missing the disclaimer or that contains a conflicting authority claim (e.g. "this
|
||||
file is authoritative"). There is deliberately no Markdown → prd.json parser, so a generated
|
||||
artifact structurally cannot feed `passes` (or anything else) back into the authoritative source.
|
||||
- CLI: `python scripts/ralph_prd_schema.py validate <prd.json> [--fresh]` and
|
||||
`... render <prd.json> <STORY-ID>`.
|
||||
|
||||
### `.scratch/distributed-gguf-runtime/prd.json`
|
||||
|
||||
- Restored the top-level `sourceOfTruth`, `qualityGates`, `milestones`, and `supersededStories`
|
||||
objects to their `HEAD` content (see "Pre-existing state" above); `userStories` was already
|
||||
identical to `HEAD` and is unchanged in content.
|
||||
- Extended `metadataSchema` (previously incomplete for this story's own acceptance criteria) with:
|
||||
`requiredStoryFields` now also lists `notes` and `blocks` (present on all 55 stories); new
|
||||
`optionalStoryFields: ["completionNotes"]`; new `hardwareValues`/`upstreamValues` enums (`model`
|
||||
is documented as an open convention, not a closed enum, since quantization/model targets are
|
||||
dynamic recipe inputs per `RALPH-CONTEXT.md`); new `typeDerivation` and `labelConventions`
|
||||
(reserved prefixes, cardinality); new `generatedArtifactDisclaimer` (the exact string generated
|
||||
artifacts must start with); extended `dependencyRules`/`authorityRule` prose to match what the
|
||||
validator enforces.
|
||||
- Reworded `sourceOfTruth`'s stale "All stories are unimplemented ... passes=false" clause, which
|
||||
was no longer accurate once DGR-017 completed.
|
||||
- Marked `DGR-018.passes = true` with `completionNotes` recording this story's outcome.
|
||||
|
||||
### `.scratch/distributed-gguf-runtime/issues/018-define-canonical-ralph-and-gitea-metadata-schema.md`
|
||||
|
||||
Regenerated via `render_issue_markdown` to reflect `passes: true` (checked acceptance criteria,
|
||||
"completed" status line, "Verified evidence" handoff line) — matching the same convention DGR-017's
|
||||
issue file already used for a completed story.
|
||||
|
||||
### `tests/test_ralph_prd_schema.py` (new)
|
||||
|
||||
108 deterministic, model-download-free, GPU-free tests:
|
||||
|
||||
- **Parse** (4 tests): real backlog parses to 55 stories; missing file, invalid JSON, and
|
||||
non-object documents raise `PrdValidationError`.
|
||||
- **Structural/semantic validation against the real backlog** (7 tests): passes `validate_schema`,
|
||||
`validate_semantics`, and the composed `validate_backlog`; unique IDs/titles; all `dependsOn`
|
||||
resolve; `blocks` matches the derived dependency graph for all 55 stories; no cycle; every
|
||||
`passes: true` story carries `completionNotes` and an existing evidence README (a durable
|
||||
invariant, not a hardcoded list of which stories have completed — that list will keep growing).
|
||||
- **Structural/semantic failure-mode fixtures** (13 tests): missing required field, bad enum, wrong
|
||||
type, empty `acceptanceCriteria`, multiple `type:` labels, duplicate ID, duplicate title, unknown
|
||||
dependency, self-dependency, dependency cycle, mismatched `blocks`, bad `evidencePath`.
|
||||
- **Fresh-backlog invariant** (3 tests): accepts all-`false`, rejects a premature `passes: true`,
|
||||
and confirms `validate_backlog` (the in-progress variant) permits completed stories.
|
||||
- **prd.json-as-source-of-truth for boilerplate** (9 tests): `qualityGates`/`metadataSchema`
|
||||
self-consistency checks (no-op without them, catches a drifted enum, catches a missing
|
||||
`qualityGates`), `quality_gate_bullets` flattening order, `authority_disclaimer` precedence and
|
||||
fallback, and 3 tests asserting the real backlog's declared schema matches the code, its 7
|
||||
quality-gate bullets are intact, and its disclaimer matches the module default.
|
||||
- **`derive_type`** (4 tests): label-derived type, release-gate synthetic type for HITL gate
|
||||
stories, `None` when absent, and confirmation that the real backlog's two release-gate stories
|
||||
(`DGR-054`, `DGR-070`) derive `release-gate`.
|
||||
- **Markdown generation round trips** (55 parametrized + 6 tests): `render_issue_markdown` for
|
||||
every story `DGR-017`..`DGR-071` is byte-for-byte identical to the corresponding file already in
|
||||
`.scratch/distributed-gguf-runtime/issues/`; determinism; leading disclaimer; `Blocks (derived)`
|
||||
rendering (`None` vs. listed); checkbox reflects `passes`; filename convention.
|
||||
- **Authority-claim rejection** (4 tests): accepts real generated text, rejects a missing
|
||||
disclaimer, rejects an overriding claim, and confirms every committed issue file in
|
||||
`.scratch/distributed-gguf-runtime/issues/` passes the check.
|
||||
- **Gitea payload generation** (3 tests): payload shape, body carries no information beyond what's
|
||||
in prd.json, and every real story's payload is well-formed and authority-clean.
|
||||
|
||||
## Commands and results
|
||||
|
||||
```bash
|
||||
python3 -m pytest -q tests/test_ralph_prd_schema.py
|
||||
```
|
||||
```text
|
||||
108 passed in 0.16s
|
||||
```
|
||||
|
||||
```bash
|
||||
python3 -m compileall -q packages tests
|
||||
```
|
||||
Exit code 0, no output (all files compile).
|
||||
|
||||
```bash
|
||||
git diff --check
|
||||
```
|
||||
Exit code 0 (no whitespace errors).
|
||||
|
||||
```bash
|
||||
python3 scripts/ralph_prd_schema.py validate .scratch/distributed-gguf-runtime/prd.json
|
||||
```
|
||||
```text
|
||||
OK: 55 stories validated.
|
||||
```
|
||||
|
||||
```bash
|
||||
python3 scripts/ralph_prd_schema.py validate .scratch/distributed-gguf-runtime/prd.json --fresh
|
||||
```
|
||||
```text
|
||||
ERROR: DGR-017: fresh backlog requires passes=false, got True
|
||||
ERROR: DGR-018: fresh backlog requires passes=false, got True
|
||||
2 validation error(s).
|
||||
```
|
||||
Expected: `--fresh` is the invariant for a backlog that hasn't started execution; this backlog has
|
||||
legitimately completed two stories, so it correctly fails that stricter check while passing the
|
||||
plain (in-progress) `validate` command above.
|
||||
|
||||
### Baseline: full repository suite (ad hoc `python3`, not a project venv)
|
||||
|
||||
```bash
|
||||
python3 -m pytest -q
|
||||
```
|
||||
```text
|
||||
20 failed, 776 passed, 13 skipped, 2 warnings in 244.17s (0:04:04)
|
||||
```
|
||||
None of the failures touch `scripts/ralph_prd_schema.py` or `tests/test_ralph_prd_schema.py`
|
||||
(neither file existed before this story; this story adds no changes to `packages/`). Four of the
|
||||
20 failures reproduce exactly the pre-existing baseline defects DGR-017's evidence already recorded
|
||||
(`test_tracker_models_endpoint_lists_registered_hf_repo_and_short_name_alias`,
|
||||
`test_torch_node_applies_tracker_load_shard_directive`,
|
||||
`test_shard_heal_cycle_surviving_node_covers_dead_peers_gap`,
|
||||
`test_a_node_with_an_unusable_precision_covers_no_layers`). The remaining 16 (activation
|
||||
compression, dynamic routing, gossip/relay, manual route benchmark, openai gateway, TOPLoC
|
||||
calibration dispatch, tracker control plane) include a `ModuleNotFoundError: langchain` failure,
|
||||
indicating this ad hoc `python3` lacks the project's `dev` extras (`langchain-openai`, etc.) rather
|
||||
than a real regression; this environment has no project virtualenv (e.g. no `.venv-rocm`) to run
|
||||
against instead. Not investigated further as out of scope for this story.
|
||||
|
||||
## Limitations
|
||||
|
||||
- No real Gitea instance or API integration exists; `to_gitea_issue_payload` defines the payload
|
||||
shape (title/body/labels/milestone) only. Creating issues against a live Gitea server is future
|
||||
work, not claimed here.
|
||||
- `model` is intentionally validated as an open string, not a closed enum, per
|
||||
`RALPH-CONTEXT.md`'s "Quantization and placement are dynamic recipe inputs" constraint; the schema
|
||||
documents (`metadataSchema.modelConvention`) but does not restrict its value set.
|
||||
- Validation and generation were exercised only against this feature's `prd.json`
|
||||
(`.scratch/distributed-gguf-runtime/prd.json`); `docs/prd.json` and other `.scratch/*/prd.json`
|
||||
files in this repo use a materially different (simpler) shape and are out of scope.
|
||||
|
||||
## Dependency handoff
|
||||
|
||||
DGR-021 and DGR-025 (this story's derived `blocks`) may treat `prd.json`'s `metadataSchema`,
|
||||
`qualityGates`, and this validator/generator as stable. Any future field addition to a story shape
|
||||
must extend `STORY_FIELDS` in `scripts/ralph_prd_schema.py` and the corresponding
|
||||
`metadataSchema.requiredStoryFields`/`optionalStoryFields` in `prd.json` together —
|
||||
`validate_metadata_schema_consistency` fails closed if they drift apart.
|
||||
@@ -1,7 +1,7 @@
|
||||
<!-- GENERATED FROM prd.json — DO NOT EDIT AS AN INDEPENDENT SOURCE. prd.json IS AUTHORITATIVE. -->
|
||||
# DGR-018: Define canonical Ralph and Gitea metadata schema
|
||||
|
||||
- **Status / triage:** specification only; `ready-for-agent`; `passes: false`
|
||||
- **Status / triage:** completed; `passes: true`
|
||||
- **Execution mode:** `AFK`
|
||||
- **Milestone:** `M0`
|
||||
- **Dependencies:** `DGR-017`
|
||||
@@ -18,11 +18,11 @@ Fresh Ralph session: read `.scratch/distributed-gguf-runtime/RALPH-CONTEXT.md`,
|
||||
|
||||
## Acceptance criteria
|
||||
|
||||
- [ ] Define fields for stable ID/title, labels, milestone, type, `dependsOn`, derived `blocks`, triage, evidence class, and hardware/model/upstream flags.
|
||||
- [ ] Validate that all stories start `passes: false`, use known dependencies, and have unique stable IDs.
|
||||
- [ ] Reject cycles, missing dependencies, mismatched generated `blocks`, duplicate titles/IDs, and generated artifacts claiming authority over `prd.json`.
|
||||
- [ ] Add deterministic model-free tests for parse, validation, and generation round trips.
|
||||
- [ ] Applicable shared quality gates in `prd.json` pass, and the evidence handoff records exact commands/results, changed files, limitations, and dependency handoff.
|
||||
- [x] Define fields for stable ID/title, labels, milestone, type, `dependsOn`, derived `blocks`, triage, evidence class, and hardware/model/upstream flags.
|
||||
- [x] Validate that all stories start `passes: false`, use known dependencies, and have unique stable IDs.
|
||||
- [x] Reject cycles, missing dependencies, mismatched generated `blocks`, duplicate titles/IDs, and generated artifacts claiming authority over `prd.json`.
|
||||
- [x] Add deterministic model-free tests for parse, validation, and generation round trips.
|
||||
- [x] Applicable shared quality gates in `prd.json` pass, and the evidence handoff records exact commands/results, changed files, limitations, and dependency handoff.
|
||||
|
||||
## Shared quality gates
|
||||
|
||||
@@ -36,4 +36,4 @@ Fresh Ralph session: read `.scratch/distributed-gguf-runtime/RALPH-CONTEXT.md`,
|
||||
|
||||
## Evidence handoff
|
||||
|
||||
Write and verify `.scratch/distributed-gguf-runtime/evidence/DGR-018/README.md`. Until every criterion and applicable gate has real evidence, this story remains `passes: false`. Legacy evidence is provenance only, not completion credit.
|
||||
Verified evidence: `.scratch/distributed-gguf-runtime/evidence/DGR-018/README.md`. Legacy evidence remains provenance only and grants no implementation completion credit.
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "Distributed GGUF Runtime",
|
||||
"branchName": "ralph/distributed-gguf-runtime",
|
||||
"description": "Benchmark-gated distributed GGUF Shards using existing Meshnet control-plane routing and a standalone C++ gRPC worker around pinned upstream llama.cpp, targeting DeepSeek V4 Flash without hardcoded quantization or topology.",
|
||||
"sourceOfTruth": "This prd.json is authoritative. Generated issue Markdown and planning summaries are projections and must not override it. All stories are unimplemented specifications with passes=false.",
|
||||
"sourceOfTruth": "This prd.json is authoritative. Generated issue Markdown and planning summaries are projections and must not override it. DGR-017 and DGR-018 are complete; all later stories remain unimplemented specifications with passes=false.",
|
||||
"qualityGates": {
|
||||
"universal": [
|
||||
"Targeted deterministic tests pass; Python changes also pass `python -m compileall packages tests`.",
|
||||
@@ -37,7 +37,12 @@
|
||||
"hardware",
|
||||
"model",
|
||||
"upstream",
|
||||
"dependsOn"
|
||||
"dependsOn",
|
||||
"notes",
|
||||
"blocks"
|
||||
],
|
||||
"optionalStoryFields": [
|
||||
"completionNotes"
|
||||
],
|
||||
"idRange": "DGR-017..DGR-071 inclusive",
|
||||
"triageValues": [
|
||||
@@ -55,8 +60,21 @@
|
||||
"real-hardware",
|
||||
"release"
|
||||
],
|
||||
"hardwareValues": [
|
||||
"none",
|
||||
"optional",
|
||||
"required"
|
||||
],
|
||||
"upstreamValues": [
|
||||
"yes",
|
||||
"no",
|
||||
"conditional"
|
||||
],
|
||||
"typeDerivation": "A story type is derived from its type:<value> label; gate:<value> stories derive release-gate.",
|
||||
"labelConventions": "Reserved prefixes include type:, priority:, area:, gate:, and ready-for-agent/ready-for-human triage labels; at most one type: and one priority: label are allowed.",
|
||||
"generatedArtifactDisclaimer": "<!-- GENERATED FROM prd.json — DO NOT EDIT AS AN INDEPENDENT SOURCE. prd.json IS AUTHORITATIVE. -->",
|
||||
"dependencyRules": "Dependencies reference existing numerically earlier IDs; graph is acyclic. blocks is mechanically derived from dependsOn.",
|
||||
"authorityRule": "Generated issue files state that prd.json is authoritative and cannot independently claim completion."
|
||||
"authorityRule": "Generated issue files state that prd.json is authoritative and cannot independently claim completion or override it."
|
||||
},
|
||||
"milestones": [
|
||||
{
|
||||
@@ -311,7 +329,8 @@
|
||||
"Add deterministic model-free tests for parse, validation, and generation round trips.",
|
||||
"Applicable shared quality gates in `prd.json` pass, and the evidence handoff records exact commands/results, changed files, limitations, and dependency handoff."
|
||||
],
|
||||
"passes": false,
|
||||
"passes": true,
|
||||
"completionNotes": "Completed 2026-07-16. Added the canonical schema/validator/generator module and 108 deterministic tests; restored and extended prd.json metadata self-description; regenerated DGR-018. See evidence/DGR-018/README.md.",
|
||||
"notes": "Generated source issue: .scratch/distributed-gguf-runtime/issues/018-define-canonical-ralph-and-gitea-metadata-schema.md; prd.json is authoritative.",
|
||||
"blocks": [
|
||||
"DGR-021",
|
||||
|
||||
Reference in New Issue
Block a user