1
0

Workspace INDEX.md + flag §07 DI non-conformance

Two changes:

1. INDEX.md (new, generated). Workspace-level index that lists every
   package grouped by UAPF level (L0/L1/L2/L3/L4) for navigation. Per
   UAPF specification §01-concepts.md, levels are an aggregation and
   governance scope only and MUST NOT be used to imply modeling
   semantics; per §04-folder-structure.md the SHOULD-recommended
   on-disk layout is enterprise/ + domains/ + processes/ regardless of
   level. INDEX.md is therefore a level-grouped *view* over the
   spec-conformant on-disk layout, not an alternative layout. Generated
   by tools/build-index/build_index.py (new), which walks the workspace
   manifests and emits INDEX.md from current state.

2. docs/methodology.md updated to document the §07 auto-layout DI as a
   known deliberate non-conformance. §07-package-format.md requires
   authored DI (from a conforming OMG modeler) and explicitly forbids
   automatic layout generation as a substitute. The DI in the five
   .bpmn files in this workspace is auto-generated by
   tools/register-transcoder/bpmn_di.py and is therefore non-conformant
   under §07. It is kept for the POC so artefacts preview visually;
   the conformant path is to re-author each .bpmn in Camunda Modeler
   or bpmn-js Studio and recommit, which emits authored DI. New
   *Known non-conformances* section in methodology.md cites §07
   verbatim and explains this rationale. The Pass-1 transcoder section
   and Final-validation-pass section are softened to call out that
   the DI is auto-generated.

uapf-cli validate green on all 13 packages (L1 domains/gramatvediba,
L2 fg1-fg6, L3 fg3-2/3/6, L4 fg3-1/4/5).
This commit is contained in:
2026-05-21 11:12:45 +00:00
parent 66ce42ea37
commit 87bab46b0f
3 changed files with 248 additions and 5 deletions

53
INDEX.md Normal file
View File

@@ -0,0 +1,53 @@
# `vk-gramatvediba` workspace index
This index lists every package in the workspace grouped by UAPF
level (L0–L4). Per UAPF specification `§01-concepts.md`, levels
are an aggregation and governance scope only; per
`§04-folder-structure.md` the SHOULD-recommended workspace layout
is `enterprise/`, `domains/`, `processes/` regardless of level.
This file is therefore a level-grouped *view* over a
spec-conformant on-disk layout, not an alternative layout.
Regenerate with `python3 tools/build-index/build_index.py`.
Total packages: **14** (L0: 1, L1: 1, L2: 6, L3: 3, L4: 3).
## L0 — Enterprise process collection index
| Package | Path | Description |
|---|---|---|
| `vk.gramatvediba` | `enterprise/enterprise.yaml` | Valsts Kase — Grāmatvedības uzskaite |
## L1 — Domain process collections
| Package | Path | Includes | Description |
|---|---|---|---|
| `vk.gramatvediba.domain` | `domains/gramatvediba/` | `../../processes/fg1`, `../../processes/fg2`, `../../processes/fg3`, `../../processes/fg4`, `../../processes/fg5`, `../../processes/fg6` | Grāmatvedības uzskaite — accounting domain |
## L2 — End-to-end business processes
| Package | Path | Includes | Description |
|---|---|---|---|
| `vk.gramatvediba.fg1` | `processes/fg1/` | _(none)_ | FG1 — Ilgtermiņa nefinanšu aktīvu un krājumu uzskaite |
| `vk.gramatvediba.fg2` | `processes/fg2/` | _(none)_ | FG2 — Finanšu aktīvu uzskaite |
| `vk.gramatvediba.fg3` | `processes/fg3/` | `../fg3-1`, `../fg3-2`, `../fg3-3`, `../fg3-4`, `../fg3-5`, `../fg3-6` | FG3 — Saistību un izdevumu uzskaite |
| `vk.gramatvediba.fg4` | `processes/fg4/` | _(none)_ | FG4 — Saistību par atlīdzību uzskaite |
| `vk.gramatvediba.fg5` | `processes/fg5/` | _(none)_ | FG5 — Prasību un ieņēmumu uzskaite |
| `vk.gramatvediba.fg6` | `processes/fg6/` | _(none)_ | FG6 — Pārskatu sagatavošana publiskošanai |
## L3 — Composed subprocesses / variants
| Package | Path | Includes | Description |
|---|---|---|---|
| `vk.gramatvediba.fg3-2` | `processes/fg3-2/` | _(none)_ | FG3-2 — Iepirkuma līguma darbības izbeigšana |
| `vk.gramatvediba.fg3-3` | `processes/fg3-3/` | _(none)_ | FG3-3 — Klienta datu pārvaldība |
| `vk.gramatvediba.fg3-6` | `processes/fg3-6/` | _(none)_ | FG3-6 — Kopsavilkuma grāmatošana |
## L4 — Atomic executable processes
| Package | Path | Cornerstones | Description |
|---|---|---|---|
| `vk.gramatvediba.fg3-1` | `processes/fg3-1/` | bpmn, dmn, resources | FG3-1 — Rēķina/kredītrēķina saņemšana par precēm/pakalpojumiem |
| `vk.gramatvediba.fg3-4` | `processes/fg3-4/` | bpmn, dmn, resources | FG3-4 — Saimnieciskā norēķina veikšana |
| `vk.gramatvediba.fg3-5` | `processes/fg3-5/` | bpmn, dmn, resources | FG3-5 — Komandējuma norēķina veikšana |

View File

@@ -114,10 +114,14 @@ one `bpmn:startEvent` per *entry step* (no in-group predecessor) and one
`bpmn:endEvent` per *exit step* (no in-group successor), so the fragment's `bpmn:endEvent` per *exit step* (no in-group successor), so the fragment's
real boundary is visible rather than hidden behind synthesised gateways. real boundary is visible rather than hidden behind synthesised gateways.
The output then has BPMN Diagram Interchange (`bpmndi:BPMNDiagram` with The output then has BPMN Diagram Interchange (`bpmndi:BPMNDiagram` with
`BPMNShape` and `BPMNEdge` elements) appended by `bpmn_di.py` using a `BPMNShape` and `BPMNEdge` elements) appended by `bpmn_di.py` via a
swim-lane left-to-right auto-layout, so the resulting file previews in swim-lane left-to-right auto-layout, so the resulting file previews in
bpmn.io, Camunda Modeler and the ProcessGit web view without manual bpmn.io, Camunda Modeler and the ProcessGit web view. **This DI is
positioning. auto-generated, not authored** — §07 of the UAPF specification requires
authored DI produced by a conforming OMG modeler and explicitly forbids
automatic layout generation as a substitute. The auto-layout output is
kept as a known deliberate non-conformance pending re-authoring of each
`.bpmn` in a modeler. See *Known non-conformances* below.
The output is `isExecutable="false"` and deliberately unembellished: no The output is `isExecutable="false"` and deliberately unembellished: no
inferred gateways, no synthesised decision logic, no compensation for inferred gateways, no synthesised decision logic, no compensation for
@@ -218,8 +222,9 @@ correction (next section):
`sourceRef`/`targetRef` nodes; every `flowNodeRef` resolves to a defined `sourceRef`/`targetRef` nodes; every `flowNodeRef` resolves to a defined
node; every `incoming`/`outgoing` reference is consistent with the node; every `incoming`/`outgoing` reference is consistent with the
corresponding flow's source/target. corresponding flow's source/target.
- All `.bpmn` files now carry BPMN Diagram Interchange — they preview - All `.bpmn` files carry BPMN Diagram Interchange (auto-generated; see
cleanly in bpmn.io, Camunda Modeler and ProcessGit's web view. *Known non-conformances* below) — sufficient for preview in bpmn.io,
Camunda Modeler and ProcessGit's web view.
- The transcoder is byte-deterministic: re-running it on the FG3 register - The transcoder is byte-deterministic: re-running it on the FG3 register
for 3.5.2 and 3.5.3 reproduces the committed `sample-output/` files for 3.5.2 and 3.5.3 reproduces the committed `sample-output/` files
exactly. exactly.
@@ -249,6 +254,31 @@ packages may reference L4 directly when no intermediate composition is
needed (`fg3` `includes` references the three L4s and the three L3 stubs needed (`fg3` `includes` references the three L4s and the three L3 stubs
in parallel, which is conformant). in parallel, which is conformant).
## Known non-conformances
This POC ships with one documented non-conformance against the UAPF
specification, retained deliberately for the POC and tracked here.
**Authored Diagram Interchange (§07-package-format.md).** §07 makes DI a
MUST for cornerstone BPMN/DMN/CMMN files and explicitly forbids automatic
layout generation as a substitute:
> "An implementation MUST NOT rely on automatic layout generation as a
> substitute for authored DI: a generated layout is not the authored
> layout and is not deterministic across tools."
The DI in the five `.bpmn` files (`fg3-1`, `fg3-4`, `fg3-5`, and the two
transcoder samples under `tools/register-transcoder/sample-output/`) is
produced by `tools/register-transcoder/bpmn_di.py` using a swim-lane
left-to-right auto-layout. It renders the diagrams in bpmn.io, Camunda
Modeler and ProcessGit's web view, but it is not authored DI and
therefore non-conformant under §07. The auto-layout is kept so the POC
artefacts are reviewable visually; the conformant path is to open each
`.bpmn` in a conforming OMG modeler (Camunda Modeler, bpmn-js Studio) and
re-save, which emits authored DI. The DMN files are unaffected — §07
exempts DMNs whose only logic is decision tables, and all three workspace
DMNs are exactly that.
## Implications for the AI regulatory sandbox ## Implications for the AI regulatory sandbox
The pipeline has four properties that bear on the sandbox's evaluation. The pipeline has four properties that bear on the sandbox's evaluation.

View File

@@ -0,0 +1,160 @@
#!/usr/bin/env python3
"""
build_index.py — generate INDEX.md from workspace manifests.
Walks the `vk-gramatvediba` workspace tree, reads every `uapf.yaml` and the
top-level `enterprise/enterprise.yaml`, groups packages by their declared
level (0–4), and emits a level-grouped index at the workspace root.
Per UAPF specification §01-concepts.md, levels are an aggregation and
governance scope only — directory structure must not encode them. Per
§04-folder-structure.md the SHOULD-recommended workspace layout is
`enterprise/` + `domains/` + `processes/` regardless of level. INDEX.md is
therefore a level-grouped *view* over a spec-conformant on-disk layout,
not an alternative layout.
Usage: python3 tools/build-index/build_index.py
Dependencies: pyyaml.
"""
import glob
import os
import sys
try:
import yaml
except ImportError:
sys.exit("error: pyyaml is required (pip install pyyaml)")
def find_workspace_root(start):
"""Walk up from `start` until a directory containing `enterprise/` is found."""
d = os.path.abspath(start)
while d != os.path.dirname(d):
if os.path.isdir(os.path.join(d, "enterprise")) and \
os.path.isdir(os.path.join(d, "processes")):
return d
d = os.path.dirname(d)
sys.exit("error: not inside a UAPF workspace (no enterprise/ + processes/)")
def read_manifest(path):
with open(path, encoding="utf-8") as fh:
return yaml.safe_load(fh)
def short(s, n=160):
if not s:
return ""
return s.split("\n")[0][:n]
LEVEL_TITLES = {
0: "L0 — Enterprise process collection index",
1: "L1 — Domain process collections",
2: "L2 — End-to-end business processes",
3: "L3 — Composed subprocesses / variants",
4: "L4 — Atomic executable processes",
}
def collect(ws):
pkgs = {0: [], 1: [], 2: [], 3: [], 4: []}
ent_path = os.path.join(ws, "enterprise", "enterprise.yaml")
if os.path.isfile(ent_path):
m = read_manifest(ent_path)
# L0 enterprise-index nests id/name/description under `enterprise:`
ent = m.get("enterprise") or m
pkgs[0].append({
"id": ent.get("id", "?"),
"name": ent.get("name", ""),
"desc": short(ent.get("description", "")),
"path": "enterprise/enterprise.yaml",
"includes": [p.get("ref", "") for p in (m.get("packages") or [])],
"cornerstones": {},
})
for pat in ("domains/*/uapf.yaml", "processes/*/uapf.yaml"):
for p in sorted(glob.glob(os.path.join(ws, pat))):
m = read_manifest(p)
lvl = m.get("level")
if lvl not in pkgs:
continue
pkgs[lvl].append({
"id": m.get("id", "?"),
"name": m.get("name", ""),
"desc": short(m.get("description", "")),
"path": os.path.relpath(os.path.dirname(p), ws) + "/",
"includes": m.get("includes") or [],
"cornerstones": m.get("cornerstones") or {},
})
return pkgs
def render(pkgs):
L = []
L.append("# `vk-gramatvediba` workspace index")
L.append("")
L.append("This index lists every package in the workspace grouped by UAPF")
L.append("level (L0–L4). Per UAPF specification `§01-concepts.md`, levels")
L.append("are an aggregation and governance scope only; per")
L.append("`§04-folder-structure.md` the SHOULD-recommended workspace layout")
L.append("is `enterprise/`, `domains/`, `processes/` regardless of level.")
L.append("This file is therefore a level-grouped *view* over a")
L.append("spec-conformant on-disk layout, not an alternative layout.")
L.append("")
L.append("Regenerate with `python3 tools/build-index/build_index.py`.")
L.append("")
total = sum(len(v) for v in pkgs.values())
L.append(f"Total packages: **{total}** "
"(L0: {0}, L1: {1}, L2: {2}, L3: {3}, L4: {4}).".format(
*(len(pkgs[i]) for i in range(5))))
L.append("")
for lvl in (0, 1, 2, 3, 4):
L.append(f"## {LEVEL_TITLES[lvl]}")
L.append("")
items = pkgs[lvl]
if not items:
L.append("_(none)_")
L.append("")
continue
if lvl == 0:
L.append("| Package | Path | Description |")
L.append("|---|---|---|")
for e in items:
desc = e["name"] or e["desc"] or ""
L.append(f"| `{e['id']}` | `{e['path']}` | {desc} |")
elif lvl in (1, 2, 3):
L.append("| Package | Path | Includes | Description |")
L.append("|---|---|---|---|")
for e in items:
inc = ", ".join(f"`{i}`" for i in e["includes"]) or "_(none)_"
desc = e["name"] or e["desc"] or ""
L.append(f"| `{e['id']}` | `{e['path']}` | {inc} | {desc} |")
else: # L4
L.append("| Package | Path | Cornerstones | Description |")
L.append("|---|---|---|---|")
for e in items:
cs = e["cornerstones"] or {}
present = [k for k in ("bpmn", "dmn", "cmmn", "resources")
if cs.get(k)]
cs_str = ", ".join(present) or "_(none)_"
desc = e["name"] or e["desc"] or ""
L.append(f"| `{e['id']}` | `{e['path']}` | {cs_str} | {desc} |")
L.append("")
return "\n".join(L) + "\n"
def main():
ws = find_workspace_root(os.path.dirname(os.path.abspath(__file__)))
pkgs = collect(ws)
text = render(pkgs)
out = os.path.join(ws, "INDEX.md")
with open(out, "w", encoding="utf-8") as fh:
fh.write(text)
print(f"wrote {out} ({sum(len(v) for v in pkgs.values())} packages)")
if __name__ == "__main__":
main()