implements PLN-0037
This commit is contained in:
parent
cbc94768a5
commit
6bd4c13d24
17
Makefile
17
Makefile
@ -1,4 +1,4 @@
|
||||
.PHONY: fmt fmt-check clippy tes-local test-debugger-socket test ci cobertura
|
||||
.PHONY: fmt fmt-check clippy test-local test-debugger-socket clean coverage coverage-xml coverage-json coverage-report-json coverage-domain-list coverage-domain-evidence test ci cobertura
|
||||
|
||||
fmt:
|
||||
cargo fmt
|
||||
@ -21,12 +21,25 @@ clean:
|
||||
coverage:
|
||||
cargo llvm-cov --workspace --all-features --html --output-dir target/llvm-cov
|
||||
|
||||
coverage-report-json:
|
||||
cargo llvm-cov report --json --output-path target/llvm-cov/report.json
|
||||
|
||||
coverage-xml:
|
||||
cargo llvm-cov report --cobertura --output-path target/llvm-cov/cobertura.xml
|
||||
|
||||
coverage-json:
|
||||
cargo llvm-cov report --json --summary-only --output-path target/llvm-cov/summary.json
|
||||
|
||||
coverage-domain-list:
|
||||
./scripts/coverage-domain-evidence.sh --list
|
||||
|
||||
coverage-domain-evidence:
|
||||
@if [ -z "$(DOMAIN)" ]; then \
|
||||
echo "usage: make coverage-domain-evidence DOMAIN=<domain>"; \
|
||||
exit 1; \
|
||||
fi
|
||||
./scripts/coverage-domain-evidence.sh "$(DOMAIN)"
|
||||
|
||||
test: fmt-check clippy test-local test-debugger-socket
|
||||
ci: clean fmt-check clippy coverage
|
||||
ci: clean fmt-check clippy coverage coverage-report-json
|
||||
cobertura: coverage-xml coverage-json
|
||||
|
||||
47
README.md
47
README.md
@ -79,6 +79,53 @@ cargo run -q -p prometeu-cli --bin prometeu -- run test-cartridges/stress-consol
|
||||
|
||||
The desktop runtime opens a native window through the host layer, so this last command is intended for a local graphical environment.
|
||||
|
||||
## Coverage Governance
|
||||
|
||||
The repository uses a two-layer runtime-edge coverage model:
|
||||
|
||||
- a mandatory global workspace coverage gate in CI;
|
||||
- domain-oriented review evidence for the canonical runtime-edge domains.
|
||||
|
||||
Current canonical domains:
|
||||
|
||||
- `system/runtime`
|
||||
- `fs`
|
||||
- `asset/bank`
|
||||
- `firmware`
|
||||
- `host-dependent`
|
||||
|
||||
Global coverage artifacts:
|
||||
|
||||
```bash
|
||||
make ci
|
||||
make cobertura
|
||||
```
|
||||
|
||||
This produces:
|
||||
|
||||
- `target/llvm-cov/html`
|
||||
- `target/llvm-cov/report.json`
|
||||
- `target/llvm-cov/summary.json`
|
||||
- `target/llvm-cov/cobertura.xml`
|
||||
|
||||
Domain-oriented evidence helpers:
|
||||
|
||||
```bash
|
||||
make coverage-domain-list
|
||||
make coverage-domain-evidence DOMAIN=firmware
|
||||
make coverage-domain-evidence DOMAIN=host-dependent
|
||||
```
|
||||
|
||||
Per-domain baselines currently start at `0`.
|
||||
That does not waive test obligations. It means the project is adopting explicit domain evidence immediately while tightening quantitative expectations incrementally over time.
|
||||
|
||||
When a PR changes the observable contract of a canonical domain, it is expected to:
|
||||
|
||||
- add or adjust tests for that domain; or
|
||||
- justify explicitly why the observable contract did not change.
|
||||
|
||||
Improving the global percentage alone is not sufficient review evidence when the changed behavior belongs to a canonical domain.
|
||||
|
||||
## Current State
|
||||
|
||||
The project is still in active architectural and implementation convergence.
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
{"type":"discussion","id":"DSC-0021","status":"done","ticket":"asset-entry-codec-enum-with-metadata","title":"Asset Entry Codec Enum Contract","created_at":"2026-04-09","updated_at":"2026-04-09","tags":["asset","runtime","codec","metadata"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0024","file":"lessons/DSC-0021-asset-entry-codec-enum-contract/LSN-0024-string-on-the-wire-enum-in-runtime.md","status":"done","created_at":"2026-04-09","updated_at":"2026-04-09"}]}
|
||||
{"type":"discussion","id":"DSC-0022","status":"done","ticket":"tile-bank-vs-glyph-bank-domain-naming","title":"Glyph Bank Domain Naming Contract","created_at":"2026-04-09","updated_at":"2026-04-10","tags":["gfx","runtime","naming","domain-model"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0025","file":"lessons/DSC-0022-glyph-bank-domain-naming/LSN-0025-rename-artifact-by-meaning-not-by-token.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
|
||||
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"legacy-runtime-learn-import","title":"Import legacy runtime learn into discussion lessons","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["migration","tech-debt"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0001-prometeu-learn-index.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0002","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0002-historical-asset-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0003","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0003-historical-audio-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0004","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0004-historical-cartridge-boot-protocol-and-manifest-authority.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0005","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0005-historical-game-memcard-slots-surface-and-semantics.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0006","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0006-historical-gfx-status-first-fault-and-return-contract.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0007","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0007-historical-retired-fault-and-input-decisions.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0008","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0008-historical-vm-core-and-assets.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0009","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0009-mental-model-asset-management.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0010","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0010-mental-model-audio.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0011","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0011-mental-model-gfx.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0012","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0012-mental-model-input.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0013","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0013-mental-model-observability-and-debugging.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0014","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0014-mental-model-portability-and-cross-platform.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0015","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0015-mental-model-save-memory-and-memcard.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0016","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0016-mental-model-status-first-and-fault-thinking.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0017","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0017-mental-model-time-and-cycles.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0018","file":"lessons/DSC-0001-runtime-learn-legacy-import/LSN-0018-mental-model-touch.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
|
||||
{"type":"discussion","id":"DSC-0002","status":"open","ticket":"runtime-edge-test-plan","title":"Agenda - Runtime Edge Test Plan","created_at":"2026-03-27","updated_at":"2026-04-20","tags":[],"agendas":[{"id":"AGD-0001","file":"workflow/agendas/AGD-0001-runtime-edge-test-plan.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-20"}],"decisions":[{"id":"DEC-0020","file":"workflow/decisions/DEC-0020-runtime-edge-coverage-governance-by-domain.md","status":"in_progress","created_at":"2026-04-20","updated_at":"2026-04-20","ref_agenda":"AGD-0001"}],"plans":[{"id":"PLN-0037","file":"workflow/plans/PLN-0037-runtime-edge-coverage-governance-foundation.md","status":"open","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]},{"id":"PLN-0038","file":"workflow/plans/PLN-0038-firmware-and-host-dependent-domain-coverage-expansion.md","status":"open","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]},{"id":"PLN-0039","file":"workflow/plans/PLN-0039-incremental-runtime-domain-suite-split-and-baselines.md","status":"open","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0002","status":"open","ticket":"runtime-edge-test-plan","title":"Agenda - Runtime Edge Test Plan","created_at":"2026-03-27","updated_at":"2026-04-20","tags":[],"agendas":[{"id":"AGD-0001","file":"workflow/agendas/AGD-0001-runtime-edge-test-plan.md","status":"done","created_at":"2026-03-27","updated_at":"2026-04-20"}],"decisions":[{"id":"DEC-0020","file":"workflow/decisions/DEC-0020-runtime-edge-coverage-governance-by-domain.md","status":"in_progress","created_at":"2026-04-20","updated_at":"2026-04-20","ref_agenda":"AGD-0001"}],"plans":[{"id":"PLN-0037","file":"workflow/plans/PLN-0037-runtime-edge-coverage-governance-foundation.md","status":"done","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]},{"id":"PLN-0038","file":"workflow/plans/PLN-0038-firmware-and-host-dependent-domain-coverage-expansion.md","status":"open","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]},{"id":"PLN-0039","file":"workflow/plans/PLN-0039-incremental-runtime-domain-suite-split-and-baselines.md","status":"open","created_at":"2026-04-20","updated_at":"2026-04-20","ref_decisions":["DEC-0020"]}],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0003","status":"open","ticket":"packed-cartridge-loader-pmc","title":"Agenda - Packed Cartridge Loader PMC","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0002","file":"workflow/agendas/AGD-0002-packed-cartridge-loader-pmc.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0004","status":"open","ticket":"system-run-cart","title":"Agenda - System Run Cart","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0003","file":"workflow/agendas/AGD-0003-system-run-cart.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
||||
{"type":"discussion","id":"DSC-0005","status":"open","ticket":"system-fault-semantics-and-control-surface","title":"Agenda - System Fault Semantics and Control Surface","created_at":"2026-03-27","updated_at":"2026-03-27","tags":[],"agendas":[{"id":"AGD-0004","file":"workflow/agendas/AGD-0004-system-fault-semantics-and-control-surface.md","status":"open","created_at":"2026-03-27","updated_at":"2026-03-27"}],"decisions":[],"plans":[],"lessons":[]}
|
||||
|
||||
@ -2,9 +2,9 @@
|
||||
id: PLN-0037
|
||||
ticket: runtime-edge-test-plan
|
||||
title: Plan - Runtime Edge Coverage Governance Foundation
|
||||
status: open
|
||||
status: done
|
||||
created: 2026-04-20
|
||||
completed:
|
||||
completed: 2026-04-20
|
||||
tags: [tests, coverage, governance, ci]
|
||||
---
|
||||
|
||||
@ -128,4 +128,3 @@ If needed, archive additional summaries or helper outputs generated by the new s
|
||||
- Overdesigning domain evidence collection before real reviewer usage patterns exist.
|
||||
- Accidentally creating a second competing coverage authority instead of a reviewer aid.
|
||||
- Spreading policy text across too many documents and making the rule hard to find.
|
||||
|
||||
|
||||
42
files/config/runtime-edge-coverage-domains.json
Normal file
42
files/config/runtime-edge-coverage-domains.json
Normal file
@ -0,0 +1,42 @@
|
||||
{
|
||||
"version": 1,
|
||||
"domains": {
|
||||
"system/runtime": {
|
||||
"baseline_percent": 0,
|
||||
"paths": [
|
||||
"crates/console/prometeu-system/src/virtual_machine_runtime.rs",
|
||||
"crates/console/prometeu-system/src/virtual_machine_runtime/"
|
||||
]
|
||||
},
|
||||
"fs": {
|
||||
"baseline_percent": 0,
|
||||
"paths": [
|
||||
"crates/console/prometeu-system/src/services/fs/",
|
||||
"crates/console/prometeu-system/src/services/memcard.rs"
|
||||
]
|
||||
},
|
||||
"asset/bank": {
|
||||
"baseline_percent": 0,
|
||||
"paths": [
|
||||
"crates/console/prometeu-hal/src/asset",
|
||||
"crates/console/prometeu-hal/src/asset.rs",
|
||||
"crates/console/prometeu-hal/src/asset_bridge.rs",
|
||||
"crates/console/prometeu-hal/src/cartridge.rs",
|
||||
"crates/console/prometeu-hal/src/cartridge_loader.rs",
|
||||
"crates/console/prometeu-drivers/src/asset.rs"
|
||||
]
|
||||
},
|
||||
"firmware": {
|
||||
"baseline_percent": 0,
|
||||
"paths": [
|
||||
"crates/console/prometeu-firmware/src/"
|
||||
]
|
||||
},
|
||||
"host-dependent": {
|
||||
"baseline_percent": 0,
|
||||
"paths": [
|
||||
"crates/host/prometeu-host-desktop-winit/src/"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
105
scripts/coverage-domain-evidence.sh
Executable file
105
scripts/coverage-domain-evidence.sh
Executable file
@ -0,0 +1,105 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(git rev-parse --show-toplevel)"
|
||||
CONFIG_PATH="${ROOT}/files/config/runtime-edge-coverage-domains.json"
|
||||
DEFAULT_REPORT="${ROOT}/target/llvm-cov/report.json"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
Usage:
|
||||
coverage-domain-evidence.sh --list
|
||||
coverage-domain-evidence.sh <domain> [report.json]
|
||||
|
||||
The report path defaults to target/llvm-cov/report.json and is expected to be
|
||||
generated by `make ci` or `make coverage-report-json`.
|
||||
EOF
|
||||
}
|
||||
|
||||
if [[ ! -f "${CONFIG_PATH}" ]]; then
|
||||
echo "missing coverage domain config: ${CONFIG_PATH}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ "$1" == "--list" ]]; then
|
||||
jq -r '.domains | keys[]' "${CONFIG_PATH}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
DOMAIN="$1"
|
||||
REPORT_PATH="${2:-${DEFAULT_REPORT}}"
|
||||
|
||||
if ! jq -e --arg domain "${DOMAIN}" '.domains[$domain]' "${CONFIG_PATH}" >/dev/null; then
|
||||
echo "unknown domain: ${DOMAIN}" >&2
|
||||
echo "available domains:" >&2
|
||||
jq -r '.domains | keys[]' "${CONFIG_PATH}" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BASELINE="$(jq -r --arg domain "${DOMAIN}" '.domains[$domain].baseline_percent' "${CONFIG_PATH}")"
|
||||
|
||||
echo "Runtime edge coverage evidence"
|
||||
echo "Domain: ${DOMAIN}"
|
||||
echo "Baseline percent: ${BASELINE}"
|
||||
echo
|
||||
|
||||
echo "Mapped repository paths:"
|
||||
jq -r --arg domain "${DOMAIN}" '.domains[$domain].paths[]' "${CONFIG_PATH}" | while IFS= read -r prefix; do
|
||||
echo " - ${prefix}"
|
||||
done
|
||||
echo
|
||||
|
||||
echo "Tracked files present in repository:"
|
||||
while IFS= read -r path; do
|
||||
(
|
||||
cd "${ROOT}"
|
||||
rg --files . | sed 's#^\./##'
|
||||
) | rg "^${path//\//\\/}" || true
|
||||
done < <(jq -r --arg domain "${DOMAIN}" '.domains[$domain].paths[]' "${CONFIG_PATH}")
|
||||
echo
|
||||
|
||||
if [[ ! -f "${REPORT_PATH}" ]]; then
|
||||
echo "Coverage report not found: ${REPORT_PATH}"
|
||||
echo "Generate it with: make coverage-report-json"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
jq -r --arg domain "${DOMAIN}" --arg root "${ROOT}" '
|
||||
.domains[$domain].paths as $paths
|
||||
| def matches_domain:
|
||||
. as $file
|
||||
| any($paths[]; . as $p | ($file.filename | startswith($root + "/" + $p) or startswith("./" + $p) or startswith($p)));
|
||||
def pct($covered; $count):
|
||||
if $count > 0 then (($covered * 10000 / $count | floor) / 100) else 0 end;
|
||||
reduce (
|
||||
input.data[]?.files[]?
|
||||
| select(matches_domain)
|
||||
) as $file (
|
||||
{
|
||||
files: [],
|
||||
lines: {count: 0, covered: 0},
|
||||
functions: {count: 0, covered: 0},
|
||||
regions: {count: 0, covered: 0}
|
||||
};
|
||||
.files += [$file.filename]
|
||||
| .lines.count += ($file.summary.lines.count // 0)
|
||||
| .lines.covered += ($file.summary.lines.covered // 0)
|
||||
| .functions.count += ($file.summary.functions.count // 0)
|
||||
| .functions.covered += ($file.summary.functions.covered // 0)
|
||||
| .regions.count += ($file.summary.regions.count // 0)
|
||||
| .regions.covered += ($file.summary.regions.covered // 0)
|
||||
)
|
||||
| "Coverage summary from " + $domain + ":",
|
||||
" files_in_report: " + (.files | length | tostring),
|
||||
" lines: " + (pct(.lines.covered; .lines.count) | tostring) + "% (" + (.lines.covered|tostring) + "/" + (.lines.count|tostring) + ")",
|
||||
" functions: " + (pct(.functions.covered; .functions.count) | tostring) + "% (" + (.functions.covered|tostring) + "/" + (.functions.count|tostring) + ")",
|
||||
" regions: " + (pct(.regions.covered; .regions.count) | tostring) + "% (" + (.regions.covered|tostring) + "/" + (.regions.count|tostring) + ")",
|
||||
"",
|
||||
"Matched report files:",
|
||||
(.files[]? | " - " + .)
|
||||
' "${CONFIG_PATH}" "${REPORT_PATH}"
|
||||
Loading…
x
Reference in New Issue
Block a user