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:
53
INDEX.md
Normal file
53
INDEX.md
Normal 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 |
|
||||
|
||||
@@ -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
|
||||
real boundary is visible rather than hidden behind synthesised gateways.
|
||||
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
|
||||
bpmn.io, Camunda Modeler and the ProcessGit web view without manual
|
||||
positioning.
|
||||
bpmn.io, Camunda Modeler and the ProcessGit web view. **This DI is
|
||||
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
|
||||
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
|
||||
node; every `incoming`/`outgoing` reference is consistent with the
|
||||
corresponding flow's source/target.
|
||||
- All `.bpmn` files now carry BPMN Diagram Interchange — they preview
|
||||
cleanly in bpmn.io, Camunda Modeler and ProcessGit's web view.
|
||||
- All `.bpmn` files carry BPMN Diagram Interchange (auto-generated; see
|
||||
*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
|
||||
for 3.5.2 and 3.5.3 reproduces the committed `sample-output/` files
|
||||
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
|
||||
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
|
||||
|
||||
The pipeline has four properties that bear on the sandbox's evaluation.
|
||||
|
||||
160
tools/build-index/build_index.py
Normal file
160
tools/build-index/build_index.py
Normal 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()
|
||||
Reference in New Issue
Block a user