From 7d9df714b9cb5a8ee302379f9d627a81ed27270b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:31:59 -0700 Subject: [PATCH 01/87] ci: verify workflow write permission --- .github/workflows/permission-probe.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/workflows/permission-probe.yml diff --git a/.github/workflows/permission-probe.yml b/.github/workflows/permission-probe.yml new file mode 100644 index 0000000..05751b4 --- /dev/null +++ b/.github/workflows/permission-probe.yml @@ -0,0 +1,13 @@ +name: Permission probe + +on: + workflow_dispatch: + +permissions: + contents: read + +jobs: + probe: + runs-on: ubuntu-latest + steps: + - run: echo "workflow path write permission confirmed" From 480a48ca59bab2b8aefe4559ebb8eb2e32bdc53c Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:33:12 -0700 Subject: [PATCH 02/87] ci: stage ELUNVERA baseline payload 01 --- .bootstrap/payload.part01 | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bootstrap/payload.part01 diff --git a/.bootstrap/payload.part01 b/.bootstrap/payload.part01 new file mode 100644 index 0000000..c79b090 --- /dev/null +++ b/.bootstrap/payload.part01 @@ -0,0 +1 @@ +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 From 210bc0854215de555a1dd9c71f25b97a77496561 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:36:40 -0700 Subject: [PATCH 03/87] ci: stage ELUNVERA baseline payload 02 --- .bootstrap/payload.part02 | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bootstrap/payload.part02 diff --git a/.bootstrap/payload.part02 b/.bootstrap/payload.part02 new file mode 100644 index 0000000..7c7d6d1 --- /dev/null +++ b/.bootstrap/payload.part02 @@ -0,0 +1 @@ +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 From b3e3c86d2016a853e52df25ecb7f82e6b59f2627 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:39:24 -0700 Subject: [PATCH 04/87] ci: stage ELUNVERA baseline payload 03 --- .bootstrap/payload.part03 | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bootstrap/payload.part03 diff --git a/.bootstrap/payload.part03 b/.bootstrap/payload.part03 new file mode 100644 index 0000000..fdbf636 --- /dev/null +++ b/.bootstrap/payload.part03 @@ -0,0 +1 @@ +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 From 58817b303190e7029e912e3c83c12f17ef49cdf9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:42:50 -0700 Subject: [PATCH 05/87] ci: stage ELUNVERA baseline payload 04 --- .bootstrap/payload.part04 | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bootstrap/payload.part04 diff --git a/.bootstrap/payload.part04 b/.bootstrap/payload.part04 new file mode 100644 index 0000000..9bff87e --- /dev/null +++ b/.bootstrap/payload.part04 @@ -0,0 +1 @@ +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 From a56287c7fafc8008c6dc87007e209803ee99881a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:45:03 -0700 Subject: [PATCH 06/87] ci: stage ELUNVERA baseline payload 05 --- .bootstrap/payload.part05 | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bootstrap/payload.part05 diff --git a/.bootstrap/payload.part05 b/.bootstrap/payload.part05 new file mode 100644 index 0000000..804355c --- /dev/null +++ b/.bootstrap/payload.part05 @@ -0,0 +1 @@ +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 From 23e1e5b824da564dbf8a09d98495a902e8fa392b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:47:13 -0700 Subject: [PATCH 07/87] ci: stage ELUNVERA baseline payload 06 --- .bootstrap/payload.part06 | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bootstrap/payload.part06 diff --git a/.bootstrap/payload.part06 b/.bootstrap/payload.part06 new file mode 100644 index 0000000..bf1551a --- /dev/null +++ b/.bootstrap/payload.part06 @@ -0,0 +1 @@ +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 From a5e4845c24430f726e1eb0e27c0bff69bbc7b10a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:49:29 -0700 Subject: [PATCH 08/87] ci: stage ELUNVERA baseline payload 07 --- .bootstrap/payload.part07 | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bootstrap/payload.part07 diff --git a/.bootstrap/payload.part07 b/.bootstrap/payload.part07 new file mode 100644 index 0000000..f370760 --- /dev/null +++ b/.bootstrap/payload.part07 @@ -0,0 +1 @@ +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 From 6d9df83a20fc4911efd2bedac2c0c918320e6cdf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:51:33 -0700 Subject: [PATCH 09/87] ci: stage ELUNVERA baseline payload 08 --- .bootstrap/payload.part08 | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bootstrap/payload.part08 diff --git a/.bootstrap/payload.part08 b/.bootstrap/payload.part08 new file mode 100644 index 0000000..9441e49 --- /dev/null +++ b/.bootstrap/payload.part08 @@ -0,0 +1 @@ ++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 From 5aed2771f2b2c498499428b94a068ca160e84b0b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:52:47 -0700 Subject: [PATCH 10/87] ci: stage ELUNVERA baseline payload 09 --- .bootstrap/payload.part09 | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bootstrap/payload.part09 diff --git a/.bootstrap/payload.part09 b/.bootstrap/payload.part09 new file mode 100644 index 0000000..5f499bb --- /dev/null +++ b/.bootstrap/payload.part09 @@ -0,0 +1 @@ +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 From 2f642e1f2298c1ec6242d2f1d3ca73efe82413b6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:54:00 -0700 Subject: [PATCH 11/87] ci: materialize verified ELUNVERA documentation baseline --- .github/workflows/bootstrap-baseline.yml | 88 ++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 .github/workflows/bootstrap-baseline.yml diff --git a/.github/workflows/bootstrap-baseline.yml b/.github/workflows/bootstrap-baseline.yml new file mode 100644 index 0000000..1a3ef48 --- /dev/null +++ b/.github/workflows/bootstrap-baseline.yml @@ -0,0 +1,88 @@ +name: Bootstrap ELUNVERA documentation baseline + +on: + push: + branches: + - docs/product-technical-baseline + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: elunvera-bootstrap-baseline + cancel-in-progress: false + +jobs: + bootstrap: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out the exact feature branch + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + ref: docs/product-technical-baseline + fetch-depth: 0 + + - name: Reconstruct, verify, and materialize the baseline + shell: bash + run: | + set -euo pipefail + cat .bootstrap/payload.part* | tr -d '\n\r\t ' | base64 --decode > /tmp/elunvera-baseline.tar.gz + echo "3d5ea6633df9edd20722a19f77ffbd9f4d88da462a561341363273dc405eb551 /tmp/elunvera-baseline.tar.gz" | sha256sum --check - + test "$(tar -tzf /tmp/elunvera-baseline.tar.gz | wc -l)" -eq 55 + tar -xzf /tmp/elunvera-baseline.tar.gz -C . + rm -rf .bootstrap + rm -f .github/workflows/bootstrap-baseline.yml + rm -f .github/workflows/permission-probe.yml + python - <<'PY' + import hashlib + import json + from pathlib import Path + + manifest = json.loads(Path("manifest.json").read_text(encoding="utf-8")) + entries = manifest["files"] + assert manifest["file_count"] == len(entries) == 54 + for entry in entries: + path = Path(entry["path"]) + assert path.is_file(), f"missing manifest file: {path}" + payload = path.read_bytes() + assert len(payload) == entry["size_bytes"], f"size mismatch: {path}" + assert hashlib.sha256(payload).hexdigest() == entry["sha256"], f"hash mismatch: {path}" + + for path in ( + "schemas/events/opportunity-stage-changed-v1.schema.json", + "schemas/events/relationship-changed-v1.schema.json", + ): + json.loads(Path(path).read_text(encoding="utf-8")) + + required = ( + "docs/PRD.md", + "docs/TRD.md", + "docs/ARCHITECTURE.md", + "docs/DATA_MODEL.md", + "docs/API_CONTRACT.md", + "docs/product-technical-gap-baseline.md", + "docs/adr/README.md", + "schemas/openapi.yaml", + "schemas/asyncapi.yaml", + ) + missing = [path for path in required if not Path(path).is_file()] + assert not missing, f"missing required files: {missing}" + PY + test ! -e .bootstrap + test ! -e .github/workflows/bootstrap-baseline.yml + test ! -e .github/workflows/permission-probe.yml + + - name: Commit the verified documentation baseline + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + test "$(git ls-files --cached | wc -l)" -eq 55 + git commit -m "docs: establish ELUNVERA product and technical baseline" + git push origin HEAD:docs/product-technical-baseline From bf6a1139086099d1e543af98822da1d88aa41411 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 05:57:39 -0700 Subject: [PATCH 12/87] ci: pause ELUNVERA baseline bootstrap during payload repair --- .github/workflows/bootstrap-baseline.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/bootstrap-baseline.yml b/.github/workflows/bootstrap-baseline.yml index 1a3ef48..5abe750 100644 --- a/.github/workflows/bootstrap-baseline.yml +++ b/.github/workflows/bootstrap-baseline.yml @@ -1,9 +1,6 @@ name: Bootstrap ELUNVERA documentation baseline on: - push: - branches: - - docs/product-technical-baseline workflow_dispatch: permissions: From dbe13875533a5127f8e5baebf3984295e02bcd52 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 06:00:04 -0700 Subject: [PATCH 13/87] ci: repair ELUNVERA baseline payload 07 --- .bootstrap/payload.part07 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bootstrap/payload.part07 b/.bootstrap/payload.part07 index f370760..04ac360 100644 --- a/.bootstrap/payload.part07 +++ b/.bootstrap/payload.part07 @@ -1 +1 @@ -RNPrKbrLZoLOogRHhnKJoK2m9eXlKJ4t4etK65DZ32oS0RBmuy/3s95h/5t7m0SeUArjuxTwJUcq4JP+NFiwcm3xKPz535zt+s/maCezpVUz+HW3ON6Cwis5F0ogcP9lS/6jMx8Ikp1IQBiM5p6gQxcPRkIIhaSdmAnaWn7inqT53ZGPl9/EX36lbcgW8xo99c0sOOTnGUEbCEN2LSOgj2MHr9PBhnlViof02V/BDlmPY/gBd0OavOCv//BvBOH3h+wNUxyHf+w69O0f7A7//CuutFcLJZh/Dy6kf2q3HhkVGj44anEz2DHn87AVcqX+F51g//XvwInsJyymLasSfCJR8DXzvPw/umL3hw0XCJcdkTnIXqNqZVVz99mU+X752XYd60ULQY32SXzhziY77PK7z561iSu49uZxsL+wrf2//g5mw5ujhJuEPVzYNjR6KrtH+OQ5Je3anQ5/yH5Fc3d/5vQFF0496CHaUxNSugKe9Q+dN4JoBWIh/Jk2WzBeKHyM9uslVXScQnoQoKAY/jyyTpiIeviD86ukbkNF9IJ7ETRBoXcpWNDOOHI7giJEMKGODRAfM/+OCYx4XDZnJjvS98zg0Y6xhjhEdEf1SQeUlu44aLOerjMSTGMmpKId+jcJUio+QdECHc73kS0BKpR5TysWhMRA/EL9n+VgskKZuEIl66xL4m+SDvxE/Xd97fHjVv5vY3vrIf93T/m/3f1eQS9/h9IloNUBUvDL7KIaCGnZ4LvyXLCM6KXr3NH9eVejJz7WTRddZ03CyUFIX3RrT7SCI51sdgRRV4JsM7ZlCu6HFNuBbNQ5qzBfankMC4vhS91slzvpmhnRjdJT3qKBNHLYxF65duehNRpK80WigV2LoLqiTwi+FiWbDMynj++eyZhIJBUT+xCUOI2sAz0Nt8cbjR0D/UAY8jE2HFSDWUj5o0x37ca+tPEhYa6to/y8Y9cxqtJ4QemlHU4E8qNM+NmuziV6PdabKWDvltpSPZFzME9FI3qZ0rVpsHLDvDuq5nexSWMvYu2l5ZLevtKlnddXlbGcTyoCUI0qBl5GUWDBKxgaH2wdUroBxTM6W0SVPHItiJwyFXfEnIOgg4DmZ2j2u67H9Si8Y0e5jDrPYrUP962pFkhAqyy8jsJSMdMlNTtXqaO+wwTzwQQM6HgK7xZjzOTQJYpL1SC2z4X15PfLFq5JBgq8vSI3Q0cRbEIwguhBeKCD/fvgf5D9f724JknJclLYxLyP/X+Nin3t/X9z62H/v9f9f30newqZRvQtyUQwC3VvOz7sHNMSDaGWnkMuwkEcHWjSkAPzaqpc5wNFpQYDj2ya0h4MKjSOCVMk7/5q0L1RdjKVTXvv7pPivPCIJrrNUy7aV1lvBjYnKLnmQmOvAPeoyaqg6vpCEM/Ep4bWDuwnsYnR3w21doBkhygzBEVjTxcFsOkEjLrQVoDz0nrmL8NbZYgIKIMURMBvKMlYfxcehNKYTaYsc+lG2p9OKK5h4J4fM4Y+YEOYJNjhSaRLGnRFvTZ5mQKX570WuOxwC6MR9ZLZdjdk0JzUWJq4yT/snX+1/d8o3lZzyhtWhTrDf5MN4FP2f2uzzf+zubrxwP9zv/Z/YwcE4N/IDIDyoXKqWCfg/Qd+MAPcUCqS2TV6yW9C8AMEqJCoUexFh5o4LkV0Y0QZEscqiq6/d/gi0qG0LbxlZ20gXh3u7628Iq7BbL27Zp0nQoNB3UmtM4afVjcIMhgxZsNovHvotqJBpS8Ea6YKErby0LZSqeqHQKMBNyPFBVCML41wdtPzQkuLAjQyeSsW7LX5clhe53wajBOnthirxntck9XScuNhxdS9MRkqP3fsUxiQwRyg6y4YahaEfrDS/wr8/83ibKi4BU6q3I//v7W16P9vbT7Y/3u1/5s7BGhnuZoWOT+n12xqjO5vG9gzstp65JvWzF/NaeEGU6UpKVZ8Nk4lFe9jI2SkOeiWTjhzr8u5aW1R42FVTkbDcF1rq0f6ZjEcoIWuxwgdFNxfuPeF62ZU9vWLqOxGLV3k6naz3xJnP0HwG6WFa9EYUIexajpn57NpfXHRVRoedq5vyE7rmZuEcYVqC15lab581xgMJXl25RUGItcdtaspgyarmeWZydKFnTfEMtdKhjKq3mf8y0j+RsIERpP2sBP8Hdr/rcJllosks/xXbQSftP/r7f6/rc3tB/2f+7X/WzvZi/JtKmDbtEoNkBC4N+O/m51RzoAJKtjyCfl1OQnmMlIBRnK8PBpOGGOsfaubLGwIxiKIcjIyIcbgaYGEFRKi3adAaUzg9xF4qU/9mJ3wMJ3C5KTfuFOeCtVpMP6gdcpEihR8NaBN1sYco04O9jWmkuRdLLPkMn7FZNiSyG0kSgoPKL0swlxISTJWGKDEzFFkGBuVl0lnNLmFdcEvJApLcApNSkMcNzwY+X+N+f/tQhEOxbiaTSkK8HKIP3sP+KT932jrv21vbD/kf+7X/m9zsdkMudR78cL0jJh731tAapr04iugeUcRnPJOjgaMWRc5AfEOhi7BIWfhXLZUBGiarqyJzTdVD0HCeaJsBk1QjwijeqkxnMTu5nihrDPLVFgBnVDmAn3h0kqGSuxcPCbAA3VXYI5HAjD8JTd6+/qmYifc0drLqQtsvOEX8F8RZa3husA3MYcUzXLtok4tNRsLV0fkeOaAgYAoWzLATIEg0LJe8q5MT9kmrhXk4uNjBFbD5vBvxL7/7gQzmfmZyoE3/FXJ4E+Wf/dbvv/m9vrD/7//dr/x2z/kxkglHzGcwhuGuoZCb5oWHyiRXVdNm8hBnpfcUFUhInYpVhnrIPxszVKRJkjpTEjI0ImakDSIKPGUX6CtEnihG72uv1oMJEkXuaJrMIIMFqIpAQIOQuotpJIIo8zg1Q4tFmajJiTrqUpbQETRrh8WCRAvSjRBXFr1omUd5IzQxrtEJf1ZJ4v5VVcGuUg32XYUqJGI1UB2StERdGJ67B0SjTIwva5NNowntaSGQsNWBXumHF6wvYUYjENaaY8m8LGy2k5QVJpSReqqJxp8uGnDjtd5WFL+SXs/xdFOSzAl158NxugY/Ze6r/b29sL+f/HD/if+7X/X+xkfa1POsG1JhYrHTKzvE8Q8PPnL9hJbebjsLZA+mmJewJXUvL+Ktix2flwjDzOcHxFSnnZ2ZC4pSirE65K0UBwxJ2d32fAJnSRIyYIpjEs6DM48YDyB5f4ZjZl5ZWr4WAgOgmC2+VKWcui92pSfAy3rgDRaHSYDrKIIOF6YsVevlDZZKd4Byd4B6einvmjpOqi1++5+4W4txutNxoiVAAu0VmovEQcmwMnwpaIxbVqCIfC41c6DVdiEbyYjQS7C14ahtj2Uc5nFkCx0UNwvmIzCTtTQxvThLYCIkrVBxk2Bvh92AX+tvb/SXHDCLXmj6NCSlj1hVSx/oqd4NP5n7b933q8/dD/cb/2/wn7/w6juPYF1J+jHm4Ls3h/VWD0pDiEIXWDEK1TzfpbigzNE2pcLT6SF32rgssR9QjmasK3VvOEgxlOalIoTfP+pc/8J6PV3Q42vWAtecun0+fvrSdAecRzrmoEa12xo88CZuVoThmpTHjmP1IN6OJlvX59uP/usdCzL8GJ3tH/EF/pqJwzL3rY7gg9BeQsJchgoV0lQLUcVb8JDQ5R+dWKAC4aYG3aayubP9jpv/P8z9pqMZlRuBVeVHBe/nZNgJ+y/4/XNxbyP2FLeLD/92j/11bZ/gO/fpHS7fGEiHDC8NXV8Iy6uqqw1uAhQ3Lq/kKClMBoguY8s/3SCMDteWxgV4KPORm+hy8u/QGRELo4p1w3mUPSl4pecAgWBsNzESIqLyoRwiDefCFUCGbC1LlvK1KwqUR9K7YmxI7F9m5yqEYlPrAbdKg5cL4/mDCG47ytJuNqhGoBvSfeBI4Pjo7AVFiGtXs9akgs/QIqkExFWJyRGM/AD4vIcIlIJWz9fo27RSopLHuxm8TcMxtxk2WIBM5iXIT+xHCVq6ockS4IHnppncExb/M2yw+plODBtJLUb9gZIQKGgpOIANCWXd9cq9JPGbblS0I1ueBvEv6B/Nv5VSuAeNh0frL9Xyv0gQsBklGp66/PAH0a/9mu/25ubK0+2P97tf9rOyTUjqXw9fHxkWujTVud7tHGA10/MXcfhjg2CIl6W7i1UT2/1hZe42iQnEaXn4ZIVFgxntUG5uPzsMbHRCrNGujVOyJZgaoAKs1AwUYJsGi1E7Zishq0lnENFVpMCYzxPTf/6gGedVh5jFnPCizGdtzeqJ4NDvgd2JnGMIoCYu0928uebG495q9IakZ0ULrZUxJAQO1CkjtSyS6pqS6M+ncRiLq0vWv/mzb9MPRHpkMnMCFNXZLp70Z2Z8nVcBa/QXMAt6JdqlLrg2X++/P/1wtSLSXoh7yu4hIr4Jev/y70f21tP9j/+7X/6ztKsWP+lYjK+LV7n+jPZLUynJEYIcKqLYLX+Y5al4yAH+UBNIvCgz2boFlJdZ+y4YVKMdNP0Rpbcm7fm4gFlnIR5fJytaL2tpDul6FbI70zfbiCnnfgnXrgTG2vYtZ2x6KOXwvXIG0gg5ZwhnsEIZR3T+KTUZAGWz9gE5cjGzWaF2EnGI5d3cCeNyFln1RXpF9ZiniD2/wzVapc3C562mocdarJbMeJRCFI2CAOuVfAFSYg5zEc0+7UuD6+s0pYVgZJL8PZnBr/HjBFv4j93yhoRg4gchduM4St1f3UfzcW+7/WHvR/7tf+b+wEWy4wRbPOmA887Uk4jlvvZWrY4rpXbgi+o1uSq6xE1lXX8w31JV2zfKQUNlnSM5gzqUiyThvVjOEmg7hgENxw4FYuh0rZxD1c9cX0lmUh6XlpNQIpr5VRIz5eViU41ac5XTk9GM3GZOG5JUDEG0//v//lP//L//Ff/+X//N//5X/7f06dKvVobskY1iBdfot2EAvARgaLMnJj8esixaSRiKPafqnvcNjgOQYiwxbzPsuM/NOJdj0rFcewUTyPcNnVKMcj7piNYxFEhCwAKOhmh6npCye5BOqVBn5hdj1Y+nvz/zeL2fuCwVhS/r2f/t/H623/f2PrAf9zz/Z/k/P/5TIB1Ne/95qaA68Leq9F4EHZXEEeU1GeqlgbCfzRqwygDsExR7Ar5/iFChM31d0qjN0lZP/hlyPi8SHjHzYXkTcSpeMr0uqcEt3oNFuEdfZN7qwtLcq3aJjNBMlpImlSFkbosALVZsjDBjdaUzmJlGm+RAp14OVS86iEiuoslMzyRMPZyxffIVFK9+T0qqNG9h3V5tiGcVGPoGdNVpO0RX/40//aRMNNDIKq71o40dlUQRRoKshzkLYS9jKxmq8PpfV4+rBr/Dz7v1VMKqmfkPa1cmX98vmfxfovlYQf7P992v/Y/ytTIHeQcSNUMP40I900mfp73gmAhB8zM1D2llxgylRcDMP6rEZzyhSBOdmt5zKY6/o8wldiz0A3+zpyHkSwfH02Epkm6z87mwv4KQMofYE9SCooNogMwQfP6sTYNeK4NrmKFLIdqNJB/q4+YxLYbDCZF5MZByZExGGYfGO748gNTQYE7BTWaHLP6wuYVWZxIDX02ehtplAqozQN735SIKlE0oRksN7FImraOBYliAXW367khqFUEWT/OAktrkL8FdY/Ebl2LS4/WPB79/+3i/PbUWGcyYXzi/6qLeCT/v/qZhv/ubH60P97v/Z/e8dIj6uUnFnjeuE3pvxyLakg8gjvs/WL7gssnmMURa/Kd5Uxl7V6FNr2hFPLRAkKcrU9vnN+DKBlIB0Q+eXELNluwc0BUkQN17OEjcQcwpMgWfDlbcKvAWPHMcFml+dviawIYB3uHEZ5YER0Q+zS621HwiDiCFqRsjx+R78geL2+LaA2GZ0l1KBE2WAcqPYKu6LBlFXl+VWmKf7zOXxyHSbWrw13Rvl7q6bc5eib4TDov7LItuoIo7mMwiLXdunJ55K+4kGw/FPbrsz9uK7HlNGywX7YMH6m/e8d7O6/OPgV9F9XNzbXFvRfH68/4D/vyf6b1fXi4FEjqaesP2zeWUGq2clO1cif5tnpLpLQ/O++zFX+i/XDwr/D8vyAufshnvtDJif90PlQFIX9fzjyDTkGf/ise6cuyefh1z9asIL03VWKUM++LmdfynpOZ/8IHfay823I+Zaz6NIJP82vuuy8m3LepeyMdNofTdu37OxbcvaPc3/RZX4cO9Sya2zLNT7NL6Oj9KNYSJZd6rFc6m4qA73Ez290X3bdL+S6y1to6Zo/rbly2TWeyDU+1aalT/gTWnmWXG5tlS/3ka4AvdBfhRlfdmlZ+HcCUunCPwqsuOzksu4/gnbiRfVpLMyys4sVuKOW/jl+8rOqrMsuJqZheeFG385Pzegvu5BYiY9kCJ2F+Jn5o2XXFcvx8ciULv2zQ5f0qv/+9n/4f+G/2IcOXuCzg97By72D/t/QE/y4/7cWvmvrf61vbz7g/+7b/+tJwwizpE+pvkIbeq8CHFpgXvpvKuCEaHQ3e0zdH9M5BXKve8/VqbmYt3Y1WnZx+2EsNoV+56MZR2Nj5r5qrGQVzH4lToDwnhPHlQZzEu0F588TFMLx0caXTud5dU126Jtu9rKbZ/+J9oyrurrIs6NuttfNPlsPluVz4nshHix6YGQElFMmmChirKVQUuJDMiXgu9VDQNBVhUDu0T8KVVfYUl+Uk7cQ/s2zL1Yffbb9eZ5tP/nhT//zk+1udjWd3jQ7K2HFDbv15HJlbbW7trX6ZOW76/C/3dXN9dVO50VN8uV51utmL3DbX8+ok6nfzfbDPa89ebIZ7hl9nKbqRf5gg3ujghi2dTcg13pDd97n1hePPtsI97m+Gu5z44vl97n2+HGwxevr65vr4R5Wt74Ivu7qeqdzVM7HBHvHvT6b1LcY3zC4q1ufU4iLjG9F3UzQa0QFj7wFG8XWzaq22p13u/3k0Web4W7Xth+H2117/NFxfXvZpTvpbj/pbnbDL2gSE0Zo+n2efRtu+ZtJiMvD8MpQ1/NqQl9grMMPbaw/cbO051Cdcic7JPES12uF5Mf1DVeIfd/ZHc9n6zDPNtfktTzZoPcSnuJjDzrpbq51N7rh4O7G1pMna7xC9L4THbeE+Cisa9o+UfZF5+4rmn/CVIQ3pcZA2Yuwcr4II/Pot+xCuYH44U9/XnrN8PlXs2AcSCyTc1fxBrKrcP4RUiBUJYhXb7LPDvuvCBe7ur7D13xkQ3B7e9sdNjWGoZE7XHm8FuZl92p6PfqVniompDjjiJlAf9mTbP74J1mXJwkvsm8pJ4ll2KfaPcwuCVQwphkFbqxhnQfjllODyS1P8174az+EMRX98Y/hj38Mo04GJccYjKgDnqb/MWU6m2GeHYQ/vg4RIy1kWhW9+qwCkeE3GKR1WhSPdtkaD9HqPa1Go+ElbCWACm5h2KLfyb6ShhJqtLnj12EZXRCZ1mcvD/vH9HTbq6vFGg3WS32RhyE2G06pZhaWTdynaDSOq/OrMeQYl66U7dX1L1boxN3dwy5O/FMnSRiM9AcHFDECAnclNIlklJtGJ9T6Oo3V4ZjbcoABtxd5Pj+jVMB5zLWqomIkyQoTbNmP/QCzT9yEIyVogc4j5tvK4cFetv6Y1D35Vj4x53DoLz8mG+0xmdp7C09xx8QK37xoP3R8yLBz8kNufPIhv1hb3/h5JuKnP+nWX/32tdw6dCf59Mun010Gw4REuJsJj3mQtn7ETHhMM+GnLjp65lV6ZixffSBnAnazaV2PMLhcLybTqMeZoidzNQ2bBWuSm679Wne19QzjYTPtBmO4Iqcr7LKdjjNtcQb+ZAuWfRYMUu/FM7r459FErf1SJmqNTdSrb3f7R9kzxLzTdBHxV9QrYjNpWt+EOwoTgo5xQ1Tfls0NLhMOL3Q7WakGCMibFTp8pRqvrL5fWyuma6srd114K16Yr4UZtfRKx/VNOBF9vcKbmGKqlUck9nN2Omh3xBiG/WEP+SOaHO3Lw6D61kjNEPLa8PNj3d3U5XB6NTvrBqdj5Zx+zOmiFfrximR1mpVpeblyXv237/Dj2Ot5SFq5uC8/AvLl8sujPdRdno7q1uEn5c2wwdjUZbPyjg9jW2R9o+3LbWOy6rd3XW9xQaDNNVwPD41Af6Lx20pyFrqP8PPgyseU4Vej+izM5H3XhP9VWJ037pZa7DdpHax1LzFliYfH3ax9EWbFt/VkNMi+DT5U9m11hrJiHdbl7Nq5GvQFsJKM9HRwwMvofH1GoMTPCZXYuvTtBs/F3godsb7OU/F5eSuhIzQRueAWI92D2SS8rXKcHZESTInn/0/h7mbj8yH8dYoD7aDXY3MgMTK9eNLPDl6Hmwqfr2w/fpJ9xi5QGFea/Edm6LP4C2+aq9mkGFXvuxVdqAz/sxIeNrzFyxU940r9HUU00jQW7guYTTdNj8IEEZsUNxB34V2qdob/yl7W3XCfXzx5nGcVKpW0DF+dT8n3y9YpNsQil/4FGj5/xj3Y7G4y8KPyNtjj7tvJyp23iNE64DIsxni/Op9UlQ7wj7r5eLe7s0sKg9dXcbfbP/9uKeKjMaH3PuB99vyqIsFKoH2nlOjky1JM16fa1zUN09oaXxl94RPm3SgRF0yvwiLUoICUTWsCDlTAJ4cj4jPUrF6ua4ms5C+JCVrI//UPdnt7X5883e0f/q1ygJ+o/26uL/A/bGw86D/+evm/p2UzZOBN31I3e70XkunBDKY0D/tFnIOjIin4GIqLYCHFC4qJH0mOJK2cpUNiUlA9qprC0UGyhm433h79kmEP2oLVWDlDrsT0lzO+xShnD8kTokEYV+zpTUqt8jlMx3IHe4EtCGT7TSM0OsORidrS4oberyrKt5KSqM5hVJMeAylCadoPl6OEX0ykxjSfML2Bqa3JqMLNfEcD8haECw8wT1AE3ZUDtBE1RGrjrtHAHGl1hrpzRddMC7yMeKnYhKmygtwVuhrCQyQMQj/86S/MEkSiDCj6dbPdcYgKZkAa+FwZmX2ciNND+tgRCcOV2cmMX40won6U/zRmR7ppQkxyt5IlxrGSH86aqzC7wySdLk0GNzflOJj3enZ+dVObvNnNFXmQykpCJtySwzbgEPH0M5DYaW2axnwYdOzeVlQ5MynoGr10hEWaS4lYi1soJWP2mYpzGMcKresy62O23M1knwnVLChmH+VAqSvkmjQtbHnrGmYuWrw0ZiV0a4MQTOJTNkuXrrzsxsp+2rNRQWUPeUnjdJeRsfU+mku9fFDfsPNbYjiuK2Jdb83MsJyplFrOGhHQEL4wScXiROE7gilTe49Dj0XJOp/p63QsE4nvLJunXI+xb8eTyltm0z9akSRjHYQNqWaFHkYzF09nlIuEJw8Lf24TKF+4Y5Vkon9/mYXFbGMDxwPGKryMd9WcKMbIfSkbkfPjV9JuSzLulhduyRLd/JDQjpR9dC9v4ucwL3vye8pkvWPqJhZJFjqQ/NXAW7TUprNNasprAC0Z7j8mD6sEn6aRwZnkFROAut6q8xIgS8X4ORNyUQ4nIvoIWn7HCKHcZSPFcSCPySqOIGJjxGRkYhPV8zAXaV608KtMwxaGfGhqLUwgd0OIFCXcfx5W91SpO4dopx2SBWF1e558kR6/iT1nAEXoE5D+YoOXmc4FYPbZ2NlroM2FuSZGc9cTrAh/AvuE6HmGSWjVfhjunPfyOAlpSlPLneBdFL9pUMfKNVrjhq9vhtyHEU2vNZj9Nw//+YX9//7x7sv93d7+yXFvd+9g9+nh88Pjf/prw4BP+P9b7t/G//bA/3nv/r/mKbNjV3on1OaBqlYJrQAgM4yOj+Ak4/4iU6zBq+GoBpFEJxzKtkU46dvgTwcCTWt/4ZdxI6QGgbe06Z2bMC77hEw7LH1bcZfk3tNidkN339vPs/3d492TF6/2D547zwuZVH8ZItGxRidtugKElUAK4CwglJm710291wjav2tTlp6EWDCUfuDFWwyfRL93hXceACR0W6KUWTgBY8/vuL1WMSj7TbZ7Pcjwx2b4zbLSEnGdhlcvzdPxDfYP9l73gmXIs+Ovewe7x/EunV2XNuRmgUaIB/Pjd6mFinCYyd9MiGG1STYda3WerIh/isghDuPh73b3/qk1lFpuMB80jRP8gy7eIpL+WpR5ZpUB4ueLZ0YFAY2ERpFt3qy7Kx1G/JLrntbzUI8+fh+Lha9wGM8M19utjXw5Os8bGkBaIufDgYaTbvp9yI5p2sWXq9Igdub4OI7B6dPDFasm2UqWFHbDb77CwOfZi/ImV8+S/qJJiDpROFa8h3CDB/3jk37YnI4PvlqcfccHv/tdfDyVyiiGY6Ux/+itcknjOJY0wlG31ZnS5HKKmLvwG+Sc04Xg74y+2e0f07yj/wbgUEZLVY6aj9wDWSEt0LgbojfMwoE02UPcNZ2vaLpF4VbfJ4RebK+BlqTrhfOe7L16SXv7cTL76ILlADDnCSRN7r7BhP7yQwvlBTAu66hzhPZBlBObFal9dOfl9cg+ZqjZ/jcuaqerhmB0qkfQRVuMmu2rMrvm8staDWTxuudCMBqftn3dFgFndz0cxBdTGk61v6NyHuH87YGWewmfD2Y8laqVSUXK8B+5dru48kHY/luxTZTm9dPy/2/vS5fbyK405zefIq12T6nKSCL3hYruCEpkldnW1iTl6pkKDXhzk+ACARgApaLLFeFf8wDTvyai5+X8JHOWu2UiE4QWl7ttIrrLIpDLXc49+/nO5Zb4oD5oJ48HMN/gnKLJbDFvHIJGefijY8FeoEPAYDrAsP5tcvHy9EkvuARvFbr0JMAQ94eBTXMxZq4lQd/bpev+5dnLY7hiJt43NzPdC81FpCe8cikjBC5FE6UMkHm9PWz2d5h8jqjemMGsSws4UZm9LKaBgTyw6hSY8BAN75uTl1jLomSSFlLSJalq2LpI22Zc8C9YxBUxXxg/W304hpOXxzvfffDnP/1H62CiXw2samyMsWDdhQvgUBTaOZMSUArbJRG8XgUmFen/qrxG5zG4b8TSVfT0F8Z/CPxgC/8h9uPoXv//mfV/qdT/+U//fqnzWb4RSwwH1Ozfwbpd9ZfSb7Fw1zv06bcXpNvWFNrvq/k91wBk+OPVE90M61s4lIvrp6IYa9w0uuFSrN7Um1bpD4Nm0v0SIJ4vPVWinQ4S/m7BnV3XG8EMYnaDPi6EPWsVbTJIMrlb/EMweBCTAUULmygHB3qRyIU1r9+DOCxl+E4GNs3rDp3H7O2kF6ljNEK3C7WgJM8WHFWeinT9oo8HVFtEa7uWrR4pNqIZNvyKoDmG945UNcpIg4G2a3C048S5xIHIHr81IWlP1/Bi7TRipURtuszANlDbyGQODw6++kpZbm/BrllvGANDsxe5J3SvlkVj9H657cpWrAW8bOPREeanBPNgQV5wYFTMlm/FCL7eiJE1NxfrtW9lIW490lxvg9JWzLgtpxFaIxVQYCcwbJ5xtxl8vHKx4qrxqqcat2UB1T9grhGRS3BoWcMEP0JLrxe5QsyQFiF0qMnsk1tSWBqNZZMA1Zfi7rbSlbrFXIfO2QZjAWvZTZRFS2U7waWQghUVq02nk+ioFSJTJ2dkxWNGdjBitOWwt+zp0aDtO9qywkasDYw0jHvN1hh7Vw8OznCBZ0AXMhSgPZgwVa17jRwsPZ+NgQZqdGaMyah6u1hz5jgjmnPvJtlNSQKw0JBAZs/oOqB8StGC52wE/IPoB5v5rRY3G+moX9h1ilPZ8UPqlBXHF1q1SCq5zfgF9AFjSgoPW54Xh3uWoANGEZg0xy0HzMok/aHaZx3hLcfMmBig8b506Nty1czReDamUr97RrpojmUEFucynd/IGtbzE+drQpUAYQKyn+1HhgKQ10ssS7z6yhDmRP58pfUoQjyAi+YLUmyp1BC+ahXoo5MGx3JhBRxkBy+4BQeC+XD/DmoF/GnXrJri2Hao44+dSlrqeq5gF/RY1L3GGAP9WurzB1ySpk6R8UjgaKjKgp0uRjDpXlsKxg11vjU5fvRzxlZMtL0uc7G6gd8v3yJf/LZGXIxOR3Y23kwMkcuDeUAhDShMWl4rFe/j+oVrhSwKRtz67YLWwQ5JDqwRsEEJBMQoc9RvzRqRCbiNLQcJjimiMUXkmeoJrKnLZZ7A2vba6d/aa3R28cKFs09qM5KMTeGyL9u4xVh5IDENJI6IKvqasUk3ilXVi840ehx/SzBOehgrjFZiXIbus1BSXYn3qhdHepnGbGPI4SQ0nCQyjrGBEmZlm4wNGBUNxxoK2lZjMmSU+8lyUqhTdUlCxLTOQ3Pt63PjLvyjqWn/lXP+9EKa5xbNy7fZDgbOFWH55KyBbfAuHNvwH/weBPU135B9ZsGDKAPW6Cp/lC2JxhdPX4xBnSKDVI9hhkodYqxgzPi2H/fckXzNSjPkobz6N+ePLejDX1k27x9VTW23mFa+maAaR84rYF3Hl8rwRcIzbY9kKyvcGCA7xe1+RYHFsRVUxHI4U0e91t45FYscMyHpV1vOlfXmprq1CNauZ0bTEsRQdEhaPzPoeoXf/YPzDTJzx+jvraKTr76CG1D7Y/MTOBTqVVo9l3ruiFpJrWuQ8E9enJy++Pb56fnFSEkwA2gP+1/PWJdVo+M+5ofwovPp+nt8k25qojHh2+j4trPtLfcnhG3Gjo3nDDQJzzouldaqtTUHtnKDyURLOZGRmcZI4fXrabR82trRSm3gsZlM5W6IHVv5/D3TvVmiGuqqNVr//kas3zKyy8juEmAQ3fRinP4wNXKaLB4eGeeDS0atHY40 +RNPrKbrLZoLOogRHhnKJoK2m9eXlKJ4t4etK65DZ32oS0RBmuy/3s95h/5t7m0SeUArjuxTwJUcq4JP+NFiwcm3xKPz535zt+s/maCezpVUz+HW3ON6Cwis5F0ogcP9lS/6jMx8Ikp1IQBiM5p6gQxcPRkIIhaSdmAnaWn7inqT53ZGPl9/EX36lbcgW8xo99c0sOOTnGUEbCEN2LSOgj2MHr9PBhnlViof02V/BDlmPY/gBd0OavOCv//BvBOH3h+wNUxyHf+w69O0f7A7//CuutFcLJZh/Dy6kf2q3HhkVGj44anEz2DHn87AVcqX+F51g//XvwInsJyymLasSfCJR8DXzvPw/umL3hw0XCJcdkTnIXqNqZVVz99mU+X752XYd60ULQY32SXzhziY77PK7z561iSu49uZxsL+wrf2//g5mw5ujhJuEPVzYNjR6KrtH+OQ5Je3anQ5/yH5Fc3d/5vQFF0496CHaUxNSugKe9Q+dN4JoBWIh/Jk2WzBeKHyM9uslVXScQnoQoKAY/jyyTpiIeviD86ukbkNF9IJ7ETRBoXcpWNDOOHI7giJEMKGODRAfM/+OCYx4XDZnJjvS98zg0Y6xhjhEdEf1SQeUlu44aLOerjMSTGMmpKId+jcJUio+QdECHc73kS0BKpR5TysWhMRA/EL9n+VgskKZuEIl66xL4m+SDvxE/Xd97fHjVv5vY3vrIf93T/m/3f1eQS9/h9IloNUBUvDL7KIaCGnZ4LvyXLCM6KXr3NH9eVejJz7WTRddZ03CyUFIX3RrT7SCI51sdgRRV4JsM7ZlCu6HFNuBbNQ5qzBfankMC4vhS91slzvpmhnRjdJT3qKBNHLYxF65duehNRpK80WigV2LoLqiTwi+FiWbDMynj++eyZhIJBUT+xCUOI2sAz0Nt8cbjR0D/UAY8jE2HFSDWUj5o0x37ca+tPEhYa6to/y8Y9cxqtJ4QemlHU4E8qNM+NmuziV6PdabKWDvltpSPZFzME9FI3qZ0rVpsHLDvDuq5nexSWMvYu2l5ZLevtKlnddXlbGcTyoCUI0qBl5GUWDBKxgaH2wdUroBxTM6W0SVPHItiJwyFXfEnIOgg4DmZ2j2u67H9Si8Y0e5jDrPYrUP962pFkhAqyy8jsJSMdMlNTtXqaO+wwTzwQQM6HgK7xZjzOTQJYpL1SC2z4X15PfLFq5JBgq8vSI3Q0cRbEIwguhBeKCD/fvgf5D9f724JknJclLYxLyP/X+Nin3t/X9z62H/v9f9f30newqZRvQtyUQwC3VvOz7sHNMSDaGWnkMuwkEcHWjSkAPzaqpc5wNFpQYDj2ya0h4MKjSOCVMk7/5q0L1RdjKVTXvv7pPivPCIJrrNUy7aV1lvBjYnKLnmQmOvAPeoyaqg6vpCEM/Ep4bWDuwnsYnR3w21doBkhygzBEVjTxcFsOkEjLrQVoDz0nrmL8NbZYgIKIMURMBvKMlYfxcehNKYTaYsc+lG2p9OKK5h4J4fM4Y+YEOYJNjhSaRLGnRFvTZ5mQKX570WuOxwC6MR9ZLZdjdk0JzUWJq4yT/snX+1/d8o3lZzyhtWhTrDf5MN4FP2f2uzzf+zubrxwP9zv/Z/YwcE4N/IDIDyoXKqWCfg/Qd+MAPcUCqS2TV6yW9C8AMEqJCoUexFh5o4LkV0Y0QZEscqiq6/d/gi0qG0LbxlZ20gXh3u7628Iq7BbL27Zp0nQoNB3UmtM4afVjcIMhgxZsNovHvotqJBpS8Ea6YKErby0LZSqeqHQKMBNyPFBVCML41wdtPzQkuLAjQyeSsW7LX5clhe53wajBOnthirxntck9XScuNhxdS9MRkqP3fsUxiQwRyg6y4YahaEfrDS/wr8/83ibKi4BU6q3I//v7W16P9vbT7Y/3u1/5s7BGhnuZoWOT+n12xqjO5vG9gzstp65JvWzF/NaeEGU6UpKVZ8Nk4lFe9jI2SkOeiWTjhzr8u5aW1R42FVTkbDcF1rq0f6ZjEcoIWuxwgdFNxfuPeF62ZU9vWLqOxGLV3k6naz3xJnP0HwG6WFa9EYUIexajpn57NpfXHRVRoedq5vyE7rmZuEcYVqC15lab581xgMJXl25RUGItcdtaspgyarmeWZydKFnTfEMtdKhjKq3mf8y0j+RsIERpP2sBP8Hdr/rcJllosks/xXbQSftP/r7f6/rc3tB/2f+7X/WzvZi/JtKmDbtEoNkBC4N+O/m51RzoAJKtjyCfl1OQnmMlIBRnK8PBpOGGOsfaubLGwIxiKIcjIyIcbgaYGEFRKi3adAaUzg9xF4qU/9mJ3wMJ3C5KTfuFOeCtVpMP6gdcpEihR8NaBN1sYco04O9jWmkuRdLLPkMn7FZNiSyG0kSgoPKL0swlxISTJWGKDEzFFkGBuVl0lnNLmFdcEvJApLcApNSkMcNzwY+X+N+f/tQhEOxbiaTSkK8HKIP3sP+KT932jrv21vbD/kf+7X/m9z/sdkMudR78cL0jJh731tAapr04iugeUcRnPJOjgaMWRc5AfEOhi7BIWfhXLZUBGiarqyJzTdVD0HCeaJsBk1QjwijeqkxnMTu5nihrDPLVFgBnVDmAn3h0kqGSuxcPCbAA3VXYI5HAjD8JTd6+/qmYifc0drLqQtsvOEX8F8RZa3husA3MYcUzXLtok4tNRsLV0fkeOaAgYAoWzLATIEg0LJe8q5MT9kmrhXk4uNjBFbD5vBvxL7/7gQzmfmZyoE3/FXJ4E+Wf/dbvv/m9vrD/7//dr/x2z/kxkglHzGcwhuGuoZCb5oWHyiRXVdNm8hBnpfcUFUhInYpVhnrIPxszVKRJkjpTEjI0ImakDSIKPGUX6CtEnihG72uv1oMJEkXuaJrMIIMFqIpAQIOQuotpJIIo8zg1Q4tFmajJiTrqUpbQETRrh8WCRAvSjRBXFr1omUd5IzQxrtEJf1ZJ4v5VVcGuUg32XYUqJGI1UB2StERdGJ67B0SjTIwva5NNowntaSGQsNWBXumHF6wvYUYjENaaY8m8LGy2k5QVJpSReqqJxp8uGnDjtd5WFL+SXs/xdFOSzAl158NxugY/Ze6r/b29sL+f/HD/if+7X/X+xkfa1POsG1JhYrHTKzvE8Q8PPnL9hJbebjsLZA+mmJewJXUvL+Ktix2flwjDzOcHxFSnnZ2ZC4pSirE65K0UBwxJ2d32fAJnSRIyYIpjEs6DM48YDyB5f4ZjZl5ZWr4WAgOgmC2+VKWcui92pSfAy3rgDRaHSYDrKIIOF6YsVevlDZZKd4Byd4B6einvmjpOqi1++5+4W4txutNxoiVAAu0VmovEQcmwMnwpaIxbVqCIfC41c6DVdiEbyYjQS7C14ahtj2Uc5nFkCx0UNwvmIzCTtTQxvThLYCIkrVBxk2Bvh92AX+tvb/SXHDCLXmj6NCSlj1hVSx/oqd4NP5n7b933q8/dD/cb/2/wn7/w6juPYF1J+jHm4Ls3h/VWD0pDiEIXWDEK1TzfpbigzNE2pcLT6SF32rgssR9QjmasK3VvOEgxlOalIoTfP+pc/8J6PV3Q42vWAtecun0+fvrSdAecRzrmoEa12xo88CZuVoThmpTHjmP1IN6OJlvX59uP/usdCzL8GJ3tH/EF/pqJwzL3rY7gg9BeQsJchgoV0lQLUcVb8JDQ5R+dWKAC4aYG3aayubP9jpv/P8z9pqMZlRuBVeVHBe/nZNgJ+y/4/XNxbyP2FLeLD/92j/11bZ/gO/fpHS7fGEiHDC8NXV8Iy6uqqw1uAhQ3Lq/kKClMBoguY8s/3SCMDteWxgV4KPORm+hy8u/QGRELo4p1w3mUPSl4pecAgWBsNzESIqLyoRwiDefCFUCGbC1LlvK1KwqUR9K7YmxI7F9m5yqEYlPrAbdKg5cL4/mDCG47ytJuNqhGoBvSfeBI4Pjo7AVFiGtXs9akgs/QIqkExFWJyRGM/AD4vIcIlIJWz9fo27RSopLHuxm8TcMxtxk2WIBM5iXIT+xHCVq6ockS4IHnppncExb/M2yw+plODBtJLUb9gZIQKGgpOIANCWXd9cq9JPGbblS0I1ueBvEv6B/Nv5VSuAeNh0frL9Xyv0gQsBklGp66/PAH0a/9mu/25ubK0+2P97tf9rOyTUjqXw9fHxkWujTVud7tHGA10/MXcfhjg2CIl6W7i1UT2/1hZe42iQnEaXn4ZIVFgxntUG5uPzsMbHRCrNGujVOyJZgaoAKs1AwUYJsGi1E7Zishq0lnENFVpMCYzxPTf/6gGedVh5jFnPCizGdtzeqJ4NDvgd2JnGMIoCYu0928uebG495q9IakZ0ULrZUxJAQO1CkjtSyS6pqS6M+ncRiLq0vWv/mzb9MPRHpkMnMCFNXZLp70Z2Z8nVcBa/QXMAt6JdqlLrg2X++/P/1wtSLSXoh7yu4hIr4Jev/y70f21tP9j/+7X/6ztKsWP+lYjK+LV7n+jPZLUynJEYIcKqLYLX+Y5al4yAH+UBNIvCgz2boFlJdZ+y4YVKMdNP0Rpbcm7fm4gFlnIR5fJytaL2tpDul6FbI70zfbiCnnfgnXrgTG2vYtZ2x6KOXwvXIG0gg5ZwhnsEIZR3T+KTUZAGWz9gE5cjGzWaF2EnGI5d3cCeNyFln1RXpF9ZiniD2/wzVapc3C562mocdarJbMeJRCFI2CAOuVfAFSYg5zEc0+7UuD6+s0pYVgZJL8PZnBr/HjBFv4j93yhoRg4gchduM4St1f3UfzcW+7/WHvR/7tf+b+wEWy4wRbPOmA887Uk4jlvvZWrY4rpXbgi+o1uSq6xE1lXX8w31JV2zfKQUNlnSM5gzqUiyThvVjOEmg7hgENxw4FYuh0rZxD1c9cX0lmUh6XlpNQIpr5VRIz5eViU41ac5XTk9GM3GZOG5JUDEG0//v//lP//L//Ff/+X//N//5X/7f06dKvVobskY1iBdfot2EAvARgaLMnJj8esixaSRiKPafqnvcNjgOQYiwxbzPsuM/NOJdj0rFcewUTyPcNnVKMcj7piNYxFEhCwAKOhmh6npCye5BOqVBn5hdj1Y+nvz/zeL2fuCwVhS/r2f/t/H623/f2PrAf9zz/Z/k/P/5TIB1Ne/95qaA68Leq9F4EHZXEEeU1GeqlgbCfzRqwygDsExR7Ar5/iFChM31d0qjN0lZP/hlyPi8SHjHzYXkTcSpeMr0uqcEt3oNFuEdfZN7qwtLcq3aJjNBMlpImlSFkbosALVZsjDBjdaUzmJlGm+RAp14OVS86iEiuoslMzyRMPZyxffIVFK9+T0qqNG9h3V5tiGcVGPoGdNVpO0RX/40//aRMNNDIKq71o40dlUQRRoKshzkLYS9jKxmq8PpfV4+rBr/Dz7v1VMKqmfkPa1cmX98vmfxfovlYQf7P992v/Y/ytTIHeQcSNUMP40I900mfp73gmAhB8zM1D2llxgylRcDMP6rEZzyhSBOdmt5zKY6/o8wldiz0A3+zpyHkSwfH02Epkm6z87mwv4KQMofYE9SCooNogMwQfP6sTYNeK4NrmKFLIdqNJB/q4+YxLYbDCZF5MZByZExGGYfGO748gNTQYE7BTWaHLP6wuYVWZxIDX02ehtplAqozQN735SIKlE0oRksN7FImraOBYliAXW367khqFUEWT/OAktrkL8FdY/Ebl2LS4/WPB79/+3i/PbUWGcyYXzi/6qLeCT/v/qZhv/ubH60P97v/Z/e8dIj6uUnFnjeuE3pvxyLakg8gjvs/WL7gssnmMURa/Kd5Uxl7V6FNr2hFPLRAkKcrU9vnN+DKBlIB0Q+eXELNluwc0BUkQN17OEjcQcwpMgWfDlbcKvAWPHMcFml+dviawIYB3uHEZ5YER0Q+zS621HwiDiCFqRsjx+R78geL2+LaA2GZ0l1KBE2WAcqPYKu6LBlFXl+VWmKf7zOXxyHSbWrw13Rvl7q6bc5eib4TDov7LItuoIo7mMwiLXdunJ55K+4kGw/FPbrsz9uK7HlNGywX7YMH6m/e8d7O6/OPgV9F9XNzbXFvRfH68/4D/vyf6b1fXi4FEjqaesP2zeWUGq2clO1cif5tnpLpLQ/O++zFX+i/XDwr/D8vyAufshnvtDJif90PlQFIX9fzjyDTkGf/ise6cuyefh1z9asIL03VWKUM++LmdfynpOZ/8IHfay823I+Zaz6NIJP82vuuy8m3LepeyMdNofTdu37OxbcvaPc3/RZX4cO9Sya2zLNT7NL6Oj9KNYSJZd6rFc6m4qA73Ez290X3bdL+S6y1to6Zo/rbly2TWeyDU+1aalT/gTWnmWXG5tlS/3ka4AvdBfhRlfdmlZ+HcCUunCPwqsuOzksu4/gnbiRfVpLMyys4sVuKOW/jl+8rOqrMsuJqZheeFG385Pzegvu5BYiY9kCJ2F+Jn5o2XXFcvx8ciULv2zQ5f0qv/+9n/4f+G/2IcOXuCzg97By72D/t/QE/y4/7cWvmvrf61vbz7g/+7b/+tJwwizpE+pvkIbeq8CHFpgXvpvKuCEaHQ3e0zdH9M5BXKve8/VqbmYt3Y1WnZx+2EsNoV+56MZR2Nj5r5qrGQVzH4lToDwnhPHlQZzEu0F588TFMLx0caXTud5dU126Jtu9rKbZ/+J9oyrurrIs6NuttfNPlsPluVz4nshHix6YGQElFMmmChirKVQUuJDMiXgu9VDQNBVhUDu0T8KVVfYUl+Uk7cQ/s2zL1Yffbb9eZ5tP/nhT//zk+1udjWd3jQ7K2HFDbv15HJlbbW7trX6ZOW76/C/3dXN9dVO50VN8uV51utmL3DbX8+ok6nfzfbDPa89ebIZ7hl9nKbqRf5gg3ujghi2dTcg13pDd97n1hePPtsI97m+Gu5z44vl97n2+HGwxevr65vr4R5Wt74Ivu7qeqdzVM7HBHvHvT6b1LcY3zC4q1ufU4iLjG9F3UzQa0QFj7wFG8XWzaq22p13u/3k0Web4W7Xth+H2117/NFxfXvZpTvpbj/pbnbDL2gSE0Zo+n2efRtu+ZtJiMvD8MpQ1/NqQl9grMMPbaw/cbO051Cdcic7JPES12uF5Mf1DVeIfd/ZHc9n6zDPNtfktTzZoPcSnuJjDzrpbq51N7rh4O7G1pMna7xC9L4THbeE+Cisa9o+UfZF5+4rmn/CVIQ3pcZA2Yuwcr4II/Pot+xCuYH44U9/XnrN8PlXs2AcSCyTc1fxBrKrcP4RUiBUJYhXb7LPDvuvCBe7ur7D13xkQ3B7e9sdNjWGoZE7XHm8FuZl92p6PfqVniompDjjiJlAf9mTbP74J1mXJwkvsm8pJ4ll2KfaPcwuCVQwphkFbqxhnQfjllODyS1P8174az+EMRX98Y/hj38Mo04GJccYjKgDnqb/MWU6m2GeHYQ/vg4RIy1kWhW9+qwCkeE3GKR1WhSPdtkaD9HqPa1Go+ElbCWACm5h2KLfyb6ShhJqtLnj12EZXRCZ1mcvD/vH9HTbq6vFGg3WS32RhyE2G06pZhaWTdynaDSOq/OrMeQYl66U7dX1L1boxN3dwy5O/FMnSRiM9AcHFDECAnclNIlklJtGJ9T6Oo3V4ZjbcoABtxd5Pj+jVMB5zLWqomIkyQoTbNmP/QCzT9yEIyVogc4j5tvK4cFetv6Y1D35Vj4x53DoLz8mG+0xmdp7C09xx8QK37xoP3R8yLBz8kNufPIhv1hb3/h5JuKnP+nWX/32tdw6dCf59Mun010Gw4REuJsJj3mQtn7ETHhMM+GnLjp65lV6ZixffSBnAnazaV2PMLhcLybTqMeZoidzNQ2bBWuSm679Wne19QzjYTPtBmO4Iqcr7LKdjjNtcQb+ZAuWfRYMUu/FM7r459FErf1SJmqNTdSrb3f7R9kzxLzTdBHxV9QrYjNpWt+EOwoTgo5xQ1Tfls0NLhMOL3Q7WakGCMibFTp8pRqvrL5fWyuma6srd114K16Yr4UZtfRKx/VNOBF9vcKbmGKqlUck9nN2Omh3xBiG/WEP+SOaHO3Lw6D61kjNEPLa8PNj3d3U5XB6NTvrBqdj5Zx+zOmiFfrximR1mpVpeblyXv237/Dj2Ot5SFq5uC8/AvLl8sujPdRdno7q1uEn5c2wwdjUZbPyjg9jW2R9o+3LbWOy6rd3XW9xQaDNNVwPD41Af6Lx20pyFrqP8PPgyseU4Vej+izM5H3XhP9VWJ037pZa7DdpHax1LzFliYfH3ax9EWbFt/VkNMi+DT5U9m11hrJiHdbl7Nq5GvQFsJKM9HRwwMvofH1GoMTPCZXYuvTtBs/F3godsb7OU/F5eSuhIzQRueAWI92D2SS8rXKcHZESTInn/0/h7mbj8yH8dYoD7aDXY3MgMTK9eNLPDl6Hmwqfr2w/fpJ9xi5QGFea/Edm6LP4C2+aq9mkGFXvuxVdqAz/sxIeNrzFyxU940r9HUU00jQW7guYTTdNj8IEEZsUNxB34V2qdob/yl7W3XCfXzx5nGcVKpW0DF+dT8n3y9YpNsQil/4FGj5/xj3Y7G4y8KPyNtjj7tvJyp23iNE64DIsxni/Op9UlQ7wj7r5eLe7s0sKg9dXcbfbP/9uKeKjMaH3PuB99vyqIsFKoH2nlOjky1JM16fa1zUN09oaXxl94RPm3SgRF0yvwiLUoICUTWsCDlTAJ4cj4jPUrF6ua4ms5C+JCVrI//UPdnt7X5883e0f/q1ygJ+o/26uL/A/bGw86D/+evm/p2UzZOBN31I3e70XkunBDKY0D/tFnIOjIin4GIqLYCHFC4qJH0mOJK2cpUNiUlA9qprC0UGyhm433h79kmEP2oLVWDlDrsT0lzO+xShnD8kTokEYV+zpTUqt8jlMx3IHe4EtCGT7TSM0OsORidrS4oberyrKt5KSqM5hVJMeAylCadoPl6OEX0ykxjSfML2Bqa3JqMLNfEcD8haECw8wT1AE3ZUDtBE1RGrjrtHAHGl1hrpzRddMC7yMeKnYhKmygtwVuhrCQyQMQj/86S/MEkSiDCj6dbPdcYgKZkAa+FwZmX2ciNND+tgRCcOV2cmMX40won6U/zRmR7ppQkxyt5IlxrGSH86aqzC7wySdLk0GNzflOJj3enZ+dVObvNnNFXmQykpCJtySwzbgEPH0M5DYaW2axnwYdOzeVlQ5MynoGr10hEWaS4lYi1soJWP2mYpzGMcKresy62O23M1knwnVLChmH+VAqSvkmjQtbHnrGmYuWrw0ZiV0a4MQTOJTNkuXrrzsxsp+2rNRQWUPeUnjdJeRsfU+mku9fFDfsPNbYjiuK2Jdb83MsJyplFrOGhHQEL4wScXiROE7gilTe49Dj0XJOp/p63QsE4nvLJunXI+xb8eTyltm0z9akSRjHYQNqWaFHkYzF09nlIuEJw8Lf24TKF+4Y5Vkon9/mYXFbGMDxwPGKryMd9WcKMbIfSkbkfPjV9JuSzLulhduyRLd/JDQjpR9dC9v4ucwL3vye8pkvWPqJhZJFjqQ/NXAW7TUprNNasprAC0Z7j8mD6sEn6aRwZnkFROAut6q8xIgS8X4ORNyUQ4nIvoIWn7HCKHcZSPFcSCPySqOIGJjxGRkYhPV8zAXaV608KtMwxaGfGhqLUwgd0OIFCXcfx5W91SpO4dopx2SBWF1e558kR6/iT1nAEXoE5D+YoOXmc4FYPbZ2NlroM2FuSZGc9cTrAh/AvuE6HmGSWjVfhjunPfyOAlpSlPLneBdFL9pUMfKNVrjhq9vhtyHEU2vNZj9Nw//+YX9//7x7sv93d7+yXFvd+9g9+nh88Pjf/prw4BP+P9b7t/G//bA/3nv/r/mKbNjV3on1OaBqlYJrQAgM4yOj+Ak4/4iU6zBq+GoBpFEJxzKtkU46dvgTwcCTWt/4ZdxI6QGgbe06Z2bMC77hEw7LH1bcZfk3tNidkN339vPs/3d492TF6/2D547zwuZVH8ZItGxRidtugKElUAK4CwglJm710291wjav2tTlp6EWDCUfuDFWwyfRL93hXceACR0W6KUWTgBY8/vuL1WMSj7TbZ7Pcjwx2b4zbLSEnGdhlcvzdPxDfYP9l73gmXIs+Ovewe7x/EunV2XNuRmgUaIB/Pjd6mFinCYyd9MiGG1STYda3WerIh/isghDuPh73b3/qk1lFpuMB80jRP8gy7eIpL+WpR5ZpUB4ueLZ0YFAY2ERpFt3qy7Kx1G/JLrntbzUI8+fh+Lha9wGM8M19utjXw5Os8bGkBaIufDgYaTbvp9yI5p2sWXq9Igdub4OI7B6dPDFasm2UqWFHbDb77CwOfZi/ImV8+S/qJJiDpROFa8h3CDB/3jk37YnI4PvlqcfccHv/tdfDyVyiiGY6Ux/+itcknjOJY0wlG31ZnS5HKKmLvwG+Sc04Xg74y+2e0f07yj/wbgUEZLVY6aj9wDWSEt0LgbojfMwoE02UPcNZ2vaLpF4VbfJ4RebK+BlqTrhfOe7L16SXv7cTL76ILlADDnCSRN7r7BhP7yQwvlBTAu66hzhPZBlBObFal9dOfl9cg+ZqjZ/jcuaqerhmB0qkfQRVuMmu2rMrvm8staDWTxuudCMBqftn3dFgFndz0cxBdTGk61v6NyHuH87YGWewmfD2Y8laqVSUXK8B+5dru48kHY/luxTZTm9dPy/2/vS5fbyK405zefIq12T6nKSCL3hYruCEpkldnW1iTl6pkKDXhzk+ACARgApaLLFeFf8wDTvyai5+X8JHOWu2UiE4QWl7ttIrrLIpDLXc49+/nO5Zb4oD5oJ48HMN/gnKLJbDFvHIJGefijY8FeoEPAYDrAsP5tcvHy9EkvuARvFbr0JMAQ94eBTXMxZq4lQd/bpev+5dnLY7hiJt43NzPdC81FpCe8cikjBC5FE6UMkHm9PWz2d5h8jqjemMGsSws4UZm9LKaBgTyw6hSY8BAN75uTl1jLomSSFlLSJalq2LpI22Zc8C9YxBUxXxg/W304hpOXxzvfffDnP/1H62CiXw2samyMsWDdhQvgUBTaOZMSUArbJRG8XgUmFen/qrxG5zG4b8TSVfT0F8Z/CPxgC/8h9uPoXv//mfV/qdT/+U//fqnzWb4RSwwH1Ozfwbpd9ZfSb7Fw1zv06bcXpNvWFNrvq/k91wBk+OPVE90M61s4lIvrp6IYa9w0uuFSrN7Um1bpD4Nm0v0SIJ4vPVWinQ4S/m7BnV3XG8EMYnaDPi6EPWsVbTJIMrlb/EMweBCTAUULmygHB3qRyIU1r9+DOCxl+E4GNs3rDp3H7O2kF6ljNEK3C7WgJM8WHFWeinT9oo8HVFtEa7uWrR4pNqIZNvyKoDmG945UNcpIg4G2a3C048S5xIHIHr81IWlP1/Bi7TRipURtuszANlDbyGQODw6++kpZbm/BrllvGANDsxe5J3SvlkVj9H657cpWrAW8bOPREeanBPNgQV5wYFTMlm/FCL7eiJE1NxfrtW9lIW490lxvg9JWzLgtpxFaIxVQYCcwbJ5xtxl8vHKx4qrxqqcat2UB1T9grhGRS3BoWcMEP0JLrxe5QsyQFiF0qMnsk1tSWBqNZZMA1Zfi7rbSlbrFXIfO2QZjAWvZTZRFS2U7waWQghUVq02nk+ioFSJTJ2dkxWNGdjBitOWwt+zp0aDtO9qywkasDYw0jHvN1hh7Vw8OznCBZ0AXMhSgPZgwVa17jRwsPZ+NgQZqdGaMyah6u1hz5jgjmnPvJtlNSQKw0JBAZs/oOqB8StGC52wE/IPoB5v5rRY3G+moX9h1ilPZ8UPqlBXHF1q1SCq5zfgF9AFjSgoPW54Xh3uWoANGEZg0xy0HzMok/aHaZx3hLcfMmBig8b506Nty1czReDamUr97RrpojmUEFucynd/IGtbzE+drQpUAYQKyn+1HhgKQ10ssS7z6yhDmRP58pfUoQjyAi+YLUmyp1BC+ahXoo5MGx3JhBRxkBy+4BQeC+XD/DmoF/GnXrJri2Hao44+dSlrqeq5gF/RY1L3GGAP9WurzB1ySpk6R8UjgaKjKgp0uRjDpXlsKxg11vjU5fvRzxlZMtL0uc7G6gd8v3yJf/LZGXIxOR3Y23kwMkcuDeUAhDShMWl4rFe/j+oVrhSwKRtz67YLWwQ5JDqwRsEEJBMQoc9RvzRqRCbiNLQcJjimiMUXkmeoJrKnLZZ7A2vba6d/aa3R28cKFs09qM5KMTeGyL9u4xVh5IDENJI6IKvqasUk3ilXVi840ehx/SzBOehgrjFZiXIbus1BSXYn3qhdHepnGbGPI4SQ0nCQyjrGBEmZlm4wNGBUNxxoK2lZjMmSU+8lyUqhTdUlCxLTOQ3Pt63PjLvyjqWn/lXP+9EKa5xbNy7fZDgbOFWH55KyBbfAuHNvwH/weBPU135B9ZsGDKAPW6Cp/lC2JxhdPX4xBnSKDVI9hhkodYqxgzPi2H/fckXzNSjPkobz6N+ePLejDX1k27x9VTW23mFa+maAaR84rYF3Hl8rwRcIzbY9kKyvcGCA7xe1+RYHFsRVUxHI4U0e91t45FYscMyHpV1vOlfXmprq1CNauZ0bTEsRQdEhaPzPoeoXf/YPzDTJzx+jvraKTr76CG1D7Y/MTOBTqVVo9l3ruiFpJrWuQ8E9enJy++Pb56fnFSEkwA2gP+1/PWJdVo+M+5ofwovPp+nt8k25qojHh2+j4trPtLfcnhG3Gjo3nDDQJzzouldaqtTUHtnKDyURLOZGRmcZI4fXrabR82trRSm3gsZlM5W6IHVv5/D3TvVmiGuqqNVr//kas3zKyy8juEmAQ3fRinP4wNXKaLB4eGeeDS0atHY40 From 47ea3f8d0b12ec000bd41f8a9d8496639596f6fc Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 27 Aug 2026 06:00:27 -0700 Subject: [PATCH 14/87] ci: rerun verified ELUNVERA baseline materialization --- .github/workflows/bootstrap-baseline.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/bootstrap-baseline.yml b/.github/workflows/bootstrap-baseline.yml index 5abe750..1a3ef48 100644 --- a/.github/workflows/bootstrap-baseline.yml +++ b/.github/workflows/bootstrap-baseline.yml @@ -1,6 +1,9 @@ name: Bootstrap ELUNVERA documentation baseline on: + push: + branches: + - docs/product-technical-baseline workflow_dispatch: permissions: From e8166dcf7b92b10fbff355f6f357967a0038865f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 27 Aug 2026 13:00:37 +0000 Subject: [PATCH 15/87] docs: establish ELUNVERA product and technical baseline --- .bootstrap/payload.part01 | 1 - .bootstrap/payload.part02 | 1 - .bootstrap/payload.part03 | 1 - .bootstrap/payload.part04 | 1 - .bootstrap/payload.part05 | 1 - .bootstrap/payload.part06 | 1 - .bootstrap/payload.part07 | 1 - .bootstrap/payload.part08 | 1 - .bootstrap/payload.part09 | 1 - .cwl/data-management.yaml | 48 ++ .github/pull_request_template.md | 38 ++ .github/workflows/bootstrap-baseline.yml | 88 --- .github/workflows/permission-probe.yml | 13 - AGENTS.md | 84 +++ CHANGELOG.md | 24 + CLAUDE.md | 34 ++ CONTRIBUTING.md | 43 ++ README.md | 78 ++- SECURITY.md | 32 ++ docs/API_CONTRACT.md | 287 ++++++++++ docs/ARCHITECTURE.md | 250 +++++++++ docs/DATA_MODEL.md | 504 ++++++++++++++++++ docs/OPERABILITY.md | 151 ++++++ docs/PRD.md | 366 +++++++++++++ docs/PRIVACY.md | 141 +++++ docs/ROADMAP.md | 84 +++ docs/SECURITY.md | 174 ++++++ docs/STORYBOARD.md | 41 ++ docs/STORYBOOK_INVENTORY.md | 99 ++++ docs/TEST_STRATEGY.md | 170 ++++++ docs/THREAT_MODEL.md | 132 +++++ docs/TRD.md | 342 ++++++++++++ docs/UML.md | 115 ++++ docs/USER_STORIES.md | 37 ++ docs/USE_CASES.md | 69 +++ docs/UX_SPEC.md | 171 ++++++ docs/VALIDATION_REPORT.md | 49 ++ docs/WIREFRAMES.md | 81 +++ docs/adr/0001-product-boundary.md | 21 + docs/adr/0002-modular-monolith.md | 21 + docs/adr/0003-keyverse-identity.md | 21 + docs/adr/0004-bitemporal-truth.md | 21 + docs/adr/0005-first-class-relationships.md | 21 + .../adr/0006-provider-neutral-integrations.md | 21 + docs/adr/0007-purpose-aware-privacy.md | 21 + docs/adr/0008-ai-human-judgment.md | 21 + docs/adr/0009-postgresql-system-of-record.md | 21 + docs/adr/0010-rust-compute-boundary.md | 21 + docs/adr/0011-contract-versioning.md | 21 + docs/adr/0012-quality-release-gates.md | 21 + docs/adr/0013-brand-and-license.md | 21 + docs/adr/0014-ux-design-system.md | 21 + docs/adr/0015-retention-disposition.md | 21 + docs/adr/0016-cwl-ecosystem-boundaries.md | 21 + docs/adr/README.md | 22 + docs/doctoring/REFERENCES.md | 59 ++ docs/doctoring/RESEARCH_BASIS.md | 29 + docs/doctoring/STANDARD_TRACEABILITY.md | 22 + docs/product-technical-gap-baseline.md | 142 +++++ ...elunvera-foundation-implementation-plan.md | 433 +++++++++++++++ ...nvera-product-technical-baseline-design.md | 67 +++ manifest.json | 334 ++++++++++++ schemas/asyncapi.yaml | 75 +++ .../opportunity-stage-changed-v1.schema.json | 57 ++ .../relationship-changed-v1.schema.json | 66 +++ schemas/openapi.yaml | 275 ++++++++++ 66 files changed, 5560 insertions(+), 111 deletions(-) delete mode 100644 .bootstrap/payload.part01 delete mode 100644 .bootstrap/payload.part02 delete mode 100644 .bootstrap/payload.part03 delete mode 100644 .bootstrap/payload.part04 delete mode 100644 .bootstrap/payload.part05 delete mode 100644 .bootstrap/payload.part06 delete mode 100644 .bootstrap/payload.part07 delete mode 100644 .bootstrap/payload.part08 delete mode 100644 .bootstrap/payload.part09 create mode 100644 .cwl/data-management.yaml create mode 100644 .github/pull_request_template.md delete mode 100644 .github/workflows/bootstrap-baseline.yml delete mode 100644 .github/workflows/permission-probe.yml create mode 100644 AGENTS.md create mode 100644 CHANGELOG.md create mode 100644 CLAUDE.md create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md create mode 100644 docs/API_CONTRACT.md create mode 100644 docs/ARCHITECTURE.md create mode 100644 docs/DATA_MODEL.md create mode 100644 docs/OPERABILITY.md create mode 100644 docs/PRD.md create mode 100644 docs/PRIVACY.md create mode 100644 docs/ROADMAP.md create mode 100644 docs/SECURITY.md create mode 100644 docs/STORYBOARD.md create mode 100644 docs/STORYBOOK_INVENTORY.md create mode 100644 docs/TEST_STRATEGY.md create mode 100644 docs/THREAT_MODEL.md create mode 100644 docs/TRD.md create mode 100644 docs/UML.md create mode 100644 docs/USER_STORIES.md create mode 100644 docs/USE_CASES.md create mode 100644 docs/UX_SPEC.md create mode 100644 docs/VALIDATION_REPORT.md create mode 100644 docs/WIREFRAMES.md create mode 100644 docs/adr/0001-product-boundary.md create mode 100644 docs/adr/0002-modular-monolith.md create mode 100644 docs/adr/0003-keyverse-identity.md create mode 100644 docs/adr/0004-bitemporal-truth.md create mode 100644 docs/adr/0005-first-class-relationships.md create mode 100644 docs/adr/0006-provider-neutral-integrations.md create mode 100644 docs/adr/0007-purpose-aware-privacy.md create mode 100644 docs/adr/0008-ai-human-judgment.md create mode 100644 docs/adr/0009-postgresql-system-of-record.md create mode 100644 docs/adr/0010-rust-compute-boundary.md create mode 100644 docs/adr/0011-contract-versioning.md create mode 100644 docs/adr/0012-quality-release-gates.md create mode 100644 docs/adr/0013-brand-and-license.md create mode 100644 docs/adr/0014-ux-design-system.md create mode 100644 docs/adr/0015-retention-disposition.md create mode 100644 docs/adr/0016-cwl-ecosystem-boundaries.md create mode 100644 docs/adr/README.md create mode 100644 docs/doctoring/REFERENCES.md create mode 100644 docs/doctoring/RESEARCH_BASIS.md create mode 100644 docs/doctoring/STANDARD_TRACEABILITY.md create mode 100644 docs/product-technical-gap-baseline.md create mode 100644 docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md create mode 100644 docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md create mode 100644 manifest.json create mode 100644 schemas/asyncapi.yaml create mode 100644 schemas/events/opportunity-stage-changed-v1.schema.json create mode 100644 schemas/events/relationship-changed-v1.schema.json create mode 100644 schemas/openapi.yaml diff --git a/.bootstrap/payload.part01 b/.bootstrap/payload.part01 deleted file mode 100644 index c79b090..0000000 --- a/.bootstrap/payload.part01 +++ /dev/null @@ -1 +0,0 @@ -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 diff --git a/.bootstrap/payload.part02 b/.bootstrap/payload.part02 deleted file mode 100644 index 7c7d6d1..0000000 --- a/.bootstrap/payload.part02 +++ /dev/null @@ -1 +0,0 @@ -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 diff --git a/.bootstrap/payload.part03 b/.bootstrap/payload.part03 deleted file mode 100644 index fdbf636..0000000 --- a/.bootstrap/payload.part03 +++ /dev/null @@ -1 +0,0 @@ -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 diff --git a/.bootstrap/payload.part04 b/.bootstrap/payload.part04 deleted file mode 100644 index 9bff87e..0000000 --- a/.bootstrap/payload.part04 +++ /dev/null @@ -1 +0,0 @@ -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 diff --git a/.bootstrap/payload.part05 b/.bootstrap/payload.part05 deleted file mode 100644 index 804355c..0000000 --- a/.bootstrap/payload.part05 +++ /dev/null @@ -1 +0,0 @@ -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 diff --git a/.bootstrap/payload.part06 b/.bootstrap/payload.part06 deleted file mode 100644 index bf1551a..0000000 --- a/.bootstrap/payload.part06 +++ /dev/null @@ -1 +0,0 @@ -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 diff --git a/.bootstrap/payload.part07 b/.bootstrap/payload.part07 deleted file mode 100644 index 04ac360..0000000 --- a/.bootstrap/payload.part07 +++ /dev/null @@ -1 +0,0 @@ -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 diff --git a/.bootstrap/payload.part08 b/.bootstrap/payload.part08 deleted file mode 100644 index 9441e49..0000000 --- a/.bootstrap/payload.part08 +++ /dev/null @@ -1 +0,0 @@ -+UOznYE0c4ibyRJ+lWnd3tMnYIUtSE9bLwX7FVqV/uhHMFsjbBgRfLnMcAKSETPWkggPG0geYabtfdAqCW3aM5+HZV6sVKjLkxM0Cd5M5wgIwBkpSgMcS6ai2I9V9T4mbXfcku3cUq13NYnXjzBpZ8MgQEbQtxLHTP8GCQYkAzJra7FD25+nvejtZbY0GmCjvc1MQWteLIDGEI/pZinPCLGv1uHQhbYGmsqwb6mmImDLDZYekm1n78JyOrf6l7b9kD+MFARW+Pzrlm06NGROcSoWeOcM0WRvlm8Q0dzuMwErvrpdEjSSnJjNmA376t0ma4C2n8B+gknSMDsSGbFl3dbekRdnJ0/G//Ltby7GF0/OnnU0ZnvF4VqUeUiBJRmVoJIvNhbEJFp62ENwiN65G+10vb6pV2MUDpSkT7C9Nvtu62Jtl78k+EcGoZ7yvZDkjWta443IoZJMuKGYQu/izus37GPnoTAvofNFaoq1nrE2BbYKsl/9W3tZGbUY9Y3RIEAxS8o1JoPPSd8kYm8n/5vEELMTBk6SIcisLFP5qnYO6g2BkOFStbdGUjnyoR74DCsbEA6LFO0SSoX0qLMT/OH45HxkbbJE2+C5yip7pT5gAJtTrGCmuD069Ky0hX6OT3IOHirH0Fow246XnWBIe2H2ZO1dgvYkt03DN3KWkq7L0VsHlgoc0tW6HT0xqlfFHQmkc8TsiQ3yQ95nHQaxkI9gd4E9fA866dnQIUFtRsGkvkPHNsG1bhDhhHxm6MndaIFgkJZYCZib9DsLILvP1/GIXXrrt7qb3FjPtpn+sKEExinihsNrtBOLMEt7tggR3mR+5Gg7AETcUQsPJCEsMJlaUHLWPqU68KwZi7U9u+LkDMKC8OerzTYYC4qEtj9USYXusZKQuxpccXar7URbJVAeIVzNod1kPcZ4KhSirSlOpxREtmHs0RrEGAmDZ71ZUs/WJrTiPvrQKHBeufaqkZK0t7qrn5mYLKVaUlMlh5oqdfQl4Fwc/l1jNQuG9RDPwYAs6k4kF49fPBtZzi64A1gUZfZJb249rxVgLo6nI3Qo5+49VpfcaiHH52/dXnZE61D54leHXAt3BcOQ7E8vqeqLDjoAJs5LNGEgNlnVKpORZfBJ6+fTJUeKeul/u2tV3zNKhN+oVIopr3iO4eaVzkSy11j2nYUF5RzskbHqYFmfvoBxzmqkdXTRleQZNHkBpDbJ5l7S424vbANG6M1KkgV5Z2aY023gpqtatjzBen/uUjVE5WhwYi7pmJjTzXLMQKPwzch5cfn0JeiXi/cudiiYziXoAGczjzBh86Yeo0aEafprmbTKs4FRgFGASf0UM0ARslYsRKpVvZsBK2O6KGxFPKsVdlBTB9FshO85z8hctJJkDLgBTbSjynJiPq4dWUrWaEmbmdpptuycN9m4vXL9z3/6j5ZO0a4M/38IuTqrFKb0zfzNSsoJdmwQPKi9QYrqYKycmsxRAKGrK5Uzm73Ri+WNpT3L5ORHOojQwg/liJZrwK7xGGPYqWvGm9iwQgp9ZIC8TZe2VmqyYhykjCyX9cA2S28U7PHITgFmwT/SxD+2V13TXQdSlSnAd6ye2wYiXVNze/87vZPq0UAXIzy1q2t458nL45FOpGfJQBGCktzxpLzOZIIfLKf009uKRcsCVSE5pfEZt4WsvBPoJ5spPx4KjzZ5cE8kM3otjvQ0xmr+vB9MElYz2rGaDK7VYzneJzKx6+VMzOu2tdJsSJUy0qx1CrY2mN0NqrPS2ArtSFhha+sCHS0wlkTHaaPkNWlDOCMKNipHG8d/UEl6p7MqtWbxnueGNIBIw0txS1ukjg85nOzNqedgtte1zHe0aj9QMaSSIta8ixusQqFyrvbeWIdO91Vx4dyQ0UNDsvzSrn1gtIPY1dxfqZGyrGXD8WaMs65tDsd1UDA93bFFO4+N9U/hQ1ZD0Pzid+ocQ7kgA1q8rLxDT9GiXPAJQyv+9ppiVc2UYpIyUBRjv4I3yF1crGogrP1ONId0y4ODq6srAs5e9Tru/vy//4+FQWpMOwXxSBfYXSXvcqPQDTKKp4x+eMH1ckHtwiz/AHrm6epebEL6xY4uyN1TsQ+1a3SdXTZl6kNsPA3TogKvVxYEWjm2ZUI/mrDwoLSh6zDIXLdwoG3L1HBYTXjqeH5zjJtC25hQtyESQ+SnkfjULT1cx9FLUEFqLs8RxZoob9Fg0aWqNlxuB6El8pRNF8pYoxixfCZ5iWXBtc4/WPfADbWnSDLGNeKc4+7yR0urkDiQI1aWsArRtTwab8QS0c7JPSkKbB9xX+Xxs9d/ELz4cvEeuN4YzhKDgcjEHbeW7Qtd4x7u5HO4eM+OLLHd+V9hGvid/m9BmN7jP/7s+V8GaKXboRH1lYODf3a++uprdMK9IechsVXZueH89F9fnZ2fnjgXrx67F785e/qUu8lZhHW0vinoThesDLCJ3MpCFnmI/PIawRbq6ksqIbNulAka8zdEZ1h52woUYA9K+B5k9/p7t7h18X+xB029ZJBKMjlBFDkPr1znO+f11ZfO+hZm9gMllxNKA6u6oBEtxAync1Kj2bYijkj5AjJJhBRGvV5KCh11fL8y64Y97rWWa2vOtqFeQK2yagtR29IrDBjJqOXy1Skyvbi+FG8izkwTsiHdcWLHHFHZgjPnvnhrld0Ne4N7VHE+t5UHhosiOsDSFqwnBSKcb0FuSIDQlvDHot1r9rCgl4vcAvj9jsiBnOcKtl0oVAFWLB7B90yAHKdBT6+ZvMnDKUB5cJ6DDnT4u7VJnaPFwWwZzBkpSS+lhaE4IGJZ/nBzPXIuF98jmB7ME/SYTj72r0btVPiR8y8XL54j6B4mcCMKlusHI/Xm8XmNcdnL22V9QUnqfPelcVmUGGNzMfOmXm/Un7PZu2tQOd+Ri2hp/9Lc/OEPIzyXt+9XXNShXck0twswYzkfr8vf0cDt5+/bWcBK+5DY0sDiWXOR2EBPzFZhbqhq9qczNQU3mNUR1EO46ImmFoP+QOEHJhiB3bEEQpm+X7jv0Z1+tZ6L7+tJCVdeOXNxjV5WV1k0+JrZAhEmiFKA8N7CeuKfK45pPnLMmuNYXp2Ny9mUncno4XRb4SMLIv2RY4HhUh9IWcqrsj5oGCaE1Ifm/whtq9miJKtsvcbp0F2nZHpINsE94lm3ona8almkia9LTxQ/wSe0ECQYDYBTQExuE4WOdX4TvVaV8UlkiSkaOXM0IJTfZDqXV4DOd41tlL+vb2nEzyht5wZZBPsH0UC+JvtXQkgIvSbPrdyEdtai9NkB10W3bYnbzBjwNDrJVuWCWD5dioqw7a+i5KTds42PJ7CTyystMloSam/je94/WgsPAkKG3dfkCHqHRg8elJHz5NfHz785ffrim5HOHQANVavhcLZc12XT+hIf4x85pzp5AK/uRKx15pOJgsNr8YR+PZ3VKDvxTJDFe+RcUaD9EEzx2ZX9NeHvI2we+Zq3fy8JJWDMPa8nml2PBx43dPl6VY5n0+JwtW5dTm7wsbpsbEzJCXAfYMYT8ksvb1s3SRfzWJteqsbg8JZH82xRTZtbnLNaceYuX311ppi0XB0+6thyxCwrTQGZW3sKV4/I1MJFvyI+ST5zx3X1nXBFezvUAHFnUTugPlb1EjeW5BjrAIJciLYjqZVdB+NEq255Cwd/fkAx1qXYvIXFRE0FvUAvBdp35y9eXDr/RH88nEwwUDiZfHko00UefnkI+gGmz30XvD44OABDjh4+MXr3RM9Dz/nhl477z3Dm5vXRgQMfnV/yT8539AV+6L1j54EhiAejrR97qKznqruJp+emndQgr39N/0VwHXSazWYPcQUPp2taJpgl9ZcQ1NxXT/JLtqVbGxccIYwL4uZQ7Bb3H7dvjXt0fjMHiuNtclzYpFv6fV8Kd9zfXx2c/rAk3/+RChMg8xQou/B9hkRx2N2QaHuk4ZFq5It3qljLe7HCpBa3QRg0/ThJYbhHB+PxL1T3Cyy14E73RkmTUWZQfLSmaihIpUuiI+kX38GaFtPq4c0cUxMmmMjz5Wv8HuTD7UOK+MzfTJAxwtfw2rEp8lawg3bRlspzJxI5PAD+zMqcoyrhJjCYi7MXz4+c/w56A1DoAw/r+R484m18OWXoM1bCyK8Da4hOyX4WiF7X+a1aMIrIYuRNBqeb6RvcHMZ0AsY+my6X5IFCJQrmpC6UskLyjXV3k6IjYOk8LmsVkYkrgqKNAQHx9uBTCOuA+VVzjewKe8G5Lvwf2S7yp5JmYDMzvtJlp+Va/tXUHD6kB5zo1Tno54edm+RVmMPUvmi+AB1wueaNMkcAB0rJdwqLSL2uu4zxEUPjKlZJ6wVcwRFV5Ri25PTsM9OTDMc6kpU4ttigB7F7EBf/ARkER1ZWXye7rSWLHyh/nJTowD+09euoNLX+VJshMS55ZOueibznDqHcf8+AZN55D9Ne72/yOUYEt4akvybTQdVO3i2dr34rF+ucky1ldRc2AeMUYt08Ar96yckKT4DnUAMxe5ynq9VidTUokZU0Vhl+NFObQf7Dd/jV64NmjmFFYCETitXD0CasdE84lDvBw78CbXii9ln+DuLmRxJHs9okEv6Tpga1jg8fyMdRkdKDLx9ZImwyr3/xUK23vEyb9CDqxXoCPPDhlyNHPQRLnPAZPx3YE1BcWCZ3TEAgrmRLtdYo4fDezHCQ/btwdARWJozp/UPyOkw4UX0ij616+sMvW3P4xUNgnRjF/MVDfvzIga15uL1XR0fPeJhyV7/8kuaxSzifn54YiWzzpqXTS7O24GXJIFG6e4TwBky+O0WvOeTGu4I3VmrDcXjUKAz93xuZX78eWSECDU61QJC2xVLAikuzbmyYp+3IUbGH1WJWj7nid12jo+PV5RNyCum0YBROYD1WGA6eYsWSbHyGGhCBNQlqube2Mqi4yZECSSPXDeZcgKTuEWpyG745Pz193pKE22Jtj92R1yh/xeB1IElkOrPr4s65uBwrlwF8wUprf62wDXp+wiCy/KFPJrGsWCo7uJWtrAJmax1+/CBhtYvp2pKsyz27QgpF7hE9UQsZGX7rlTVdMWWUx77EYulU45iedKwxtsCQzFJuh7HJ6aXWi5b1cbj+fVtm7XNPBeb81o0smyxf0diycXicXVk3nTcroQuBxgSitq4J1aF1HWNAYNELpcHUrhnb4frttnwzIAl7SDjF7nWR2pUxyDj7s/3dNaEC43cUMrWu6S15u7K9JdbFra/Jh1xOl4Jv4VqxiczZwW+UB9mIG/yWHMcTKs/CP9mJKv++U9Ia0Ajbv6fl7iXXAiNag5XD3vHvoe+OkjmwRAgGiMFQpTW2U/ZH7eogvtbyEOMJnlGFiq6YY2gMjH0KEFNrlYn/HrPN7YyoLWl0gVlZ2rXWCnar7sEtWWUp+4sKDAZHEqLjNs4OEkWG2BdHI6YKQ3Qxx4gB0tuKOtuv3cPBxsF8UYolvqrLAbsy0RyB/YXiHO0mLpTVtyuJKDcGnXiYXoNOQiCpzXrzhxVW5VyxiBwzAascW/hubTZxXP+gOn+1HP5IHDor84aAPCzvv8vO1C7DBBGK4SGdvMjFVRIvEiM/SnRLoVrggzFfBXgFJxGj7/5xn+knuYhNDSQyt+nhcLyb9XyGfeUjhkBg1Jtni75HWoJsMKqx7ggAa6FJNPaIvfP6GtEg9XmQ6QBW/oUtEj/fEcCpOO47LWQ179iSFJ1XOHLRnW1mPixwuwE6vUJYMME70RW3kX02utXzWwUP0icjfS13mYn8tImqiL7D2lOSZK+LOwJlr3u+kqbjV7vMxN1ykh8p60GesGcFpQ5//xJnYH3LHabtkIb1o3yIqTwk4xGf0P7Kvr31i9wLWZhMqvG235giUxwy3GHJctoyn1R6EJLG2gmwN9udMpSiGEobpSoyI0CfcGBVldLjKnEDVRk7skt4Rs7cxdBMi+AspcCKIbuLlQvriNmobNBZXeU5nkKH22LPkiu/q120UJSkHck6MgZD6YhnSwozl9BJcEq6q1J8VcF4+FFGYeeU4Hfto4Df9NL71U5Bp/yukk6K+q14N12scBy/qeFi8QakMpXHTufvsHiZmwxjtYWM9pC5OSIkKsxjwuA9PGVKUO2CUF1qNJIxdPYW5DGWU3UjWECYN7MW1u6hc7KQONYbPliOkHFIq6BJFRQMG3ia2BgIWaWV6f65d5p7H7/uW0Zhy6O40w7ss+n4AJE2MJU1h7o6zSDpdMw9fuKAtLvLyLPMuX5hMu2KhG1RwImRXXESt/wPKklio/It2BXdTs/XaflD4kQsl+uxkrATsZwOuRq3L0SBgNTflQj9VyIGipFb6w+6qd1Y/s47WRJhlxbNrLtSqQ9f8C75NH7n6+Gj8MC/ZW6O+rM10KtHzvnXT5w8ilN5lh85p5fizaPt7WlLEh2csXZUa6/KO3iX5Ggl4XSsLukeHCNvwmwiIyXkL3YKDmrqiMhzXbvwL/7HUtzOFkJhGFq/wvKS+bjRl2BQBfjVhgrtQDpcnTXuM3QQXnVEArAt1vBQQ+J7Ca5PQdQ3Na8i9eD+KGlgE4nSpltUsh/PxzQfhykT3/RblVmuW3sxbY2Mp88uWJwrV9v1tKpmNdY7KJQkS2pYZgg2N53XtkFDmfQ3K009DLwBlMVLdQ1WrpQdm4WKiwEdw/9cOyf1BuOafaxfzUMTjQYdtZnd8JKqSJayaJTL0zWIRcvbLo8mMlXik96oltEckrMTA5NEsnLzQWwZGYRG05SD6+fMnNBms1bU7a0QEIyry5QTm0TklskUs60UO5MHtB875ufsx5HltUNMWarplk004cHeFSaSktwMfXfGh+2ek+4ic+sQF27Brd7BhlU5QUte2pCrlMchDYAX77gw5aUeQkdp70sSVD1r7mSxuiwXD6SsyyVtdoVgHPrkvKReCXiGLfQf2QeMK3hMZXPFOaRWLYC8RJIUFj5N51Idqzfv61rhc1r1r+xIA4Jz4Q+8WcM4aGeGYUiYWYGT4fwTM0BgHRYiBOE0fQTTZSa7RQgdl8VuvoupfeQDlPXV9O/pXO5UTXmRUoGTj1cuJxU4KTggNcLIxmpT1IKq2VALbWMR7iirlAZct0+QgFPJnarUzLRE3xk8katlsk2okAjEKYNDAlWCEkB+NEURzhrNSgwImVyF1TWnPmBDrWbKKXh6IG+BCD+YT3b5iTPIN5xBBiHjKL2Hu5/vKlA9YcHCYWCEaLKSHYPYFu+y3/TIeYyBe1XXpfCGe7KcdR7vnsy3LsYtBidr5NZjzmudMCLD+Gr3I9Zc5H/XZXVQq6V0F5JrHVL7z816O/4g0ZMp+ND9TVSrsef5kXvzg8zAdRlVao9QRZdtwnSvRryWTqE4DLehGfWg3Y3Z1Nws3rzBaJLOSq9W4j0yRwUA8E65NLBZAhUOtrkyAy7iQbDycGUG7p3sfYtpy4iXQkpYMa0wnAgVsq5uyZ3Cl+kyf1i77zcLdGPg1KhvWEHgIwwxPXJO52+QHY14Hsg7sKoVC0+vl1TatKFqL6MAY0yirgxUJWJEgA0rGL4MiJZa462xwEsPkxC4eaxftyBCEForeqRc85QFjRUNpYQy7OHVbeFlQERwOCYnvNVoTFsMoNtz8TdRAQxZt8robDJoSyV6e4gSsPaR1c+l4LIwXruxXDqYHVrwtGhsHZC5PmJtH9PaXQ2FuLwdWUTDLnuq81z3CI/f7grBzJfXIHyq6crZOobEuu6+wl2rxdt97dKsKj24P+Ky1iEXq8nTrpBLy61MPLKFEaOkn8UN18CJqfrm15fPnlJdAAaN6CDW87dY1ikzpaXA5HNs7Q6oDDrNm9oWwoZTWr3WKMrFbLFyybxhQJoe2aNNDAtwRmnJdpEg465sRw52rTUCbt2xc8BLODXuzg3GJDoZ8v/LUcOQ4MVLe0UNhSuGAxS7pZ/2onUlaHbEeJq1Qp5Su2CKORkRq9XSjCtQ1eG/I1ihQTbGe/h8ON//jkg+WGez8e4QvoI44/i9ST+gjtYS/GJsVydKoA8pVNs3GL3PvkUug6uL7vvk8YuXp+emJdb273fC6H9s4vuVXMo/kHdKIonwH4SDjf9EMBFGj5mtRxaopVSru/uMuCXTpl7f7X7iV1v4KlZFsIWx1jGSFO6JgWlmbzX2Nz55PDLAEZydrYMFJC/e4wDGIKnGhIFCWU8jbni0VhDqyKkkGBOi/qhaMTkchNB+N10t5gw1JFE1FCL2+PzphbRpx5a2y6oxnJN9zCOZEgwislYNXcxySGA1IuRHhBZWboxHrl1cqWTHXh4rG60FVwUHcwwcY9DaoXiMzJXDWIBQ0l4JCNmEC1ZjebMhaV/WzQ1iwcAib0PztXvmGmTBuj11dnKWoi/eI1OqNaZGCyBI0yeBwm67q/7SCdKyAg8j33fnSX9UaGMv39qd2QQ9Fxg2uVt6cR5DV4XhfrFteFIKnNRr1ZOcrFPW12ivyNJFtJfvYeEtKCdEN+nRGV5RyZXZ4f6kgk6enYXVi86/HdH/nSnhi+X6yFBcX2GEYUhqgFq8Uv2z5ZKRNVyX7ZoAK6GQfcPvUfcRNqYIwdXaxcIaTRO/t0JIulBYmjlWZLXVMAAbCiP76S8nHpFFtoc9vST8kul8TXyKrjcpNN0Ih0GqUyXSRBcyAZkBJhXgrOQZulMxRgm4T50NNELIefdQDP858B8+rT74I/AffC/xow7+QxTc9//5a/X/oeNtOknofj/ccoqbAJ309/e5IF2CQHlB1ViAZsRfq448J606Xa6NVbgKWv5J1C4qnlb5Z22VSbXpQYUZkedMBa6Fh9NtRIP1g9S5p6fdyuPgMcWHuOU7Mtg5OdvbipoCeTPA5oqviWKNlXTY5bv6nSgp3GS3/lisZEs0vORmblcQaGAgVQkte8qgCw29SnXFWF8C3d5s6319A5oIY+bjoBWIw8HBi+1GKNTmmjqhjJRvdm31OSH37Fyy9FbvAxmrtJsaUROhBUaFEWyBeAaoeNxOZ01rBZIAix453aeAhdHhkDUtiIpVKMhNFn74tBkKSYSGQ5y9hUTmt5XdYobl4iuQ0TfkVuMSGIVyRi4qErotVybnL92STSJ7vUypE4xBPGOHKkFDLHSGjeXWU50cjs/kAoh3iylF8hcMI9wKO7EphDOXYJGY18g9MGQWlN1HZ213njVtcEwTUYZxXaxMU7lZbWVYWQthWrevLEg7Jpe6ki5YSm/sNAtiJW77SLQQr4iy6PFq2VrL3IG4YjwCOkuq3Xd7lXTI6lB5is25aXXUUSdO2SpGRQYGI4ES9+jnIvFGFSx2q1UH6SuygTtwKuqeAXSFGim35FFcUYOime5N1GPps7ZS+sAOSgrwd6lT/RX4755dlTSAxUh2kBk5VguZkfMUOCcQr/zrXMy/l/8cALocEcglQntazSoulMvyBKFUX8JsMVWZhIJ82jBG4qomWx9oD0wZPEwWCzlU7SpslBuplhNoT4d/U+u2fvwbOgRtWBux7iLbjHpjzCMd1uI426jVJUZyD2YrFngIz1mhw9gYJdoJdIiuopuZ3dvkWnyP1hXKJuW6hSco+loupIavxBKfPopvY0LeFPhSXdmTWCPeypRaAbCdzuCCtE+VFveI9G+WQobUH8EPsuqi7sEVwZ8xlx94Fw7iHQqhjZ3W3e4pg5frrHw2ZOjIErNydSEB6gJ4qX3me7JhrSG20Uqo+xB/zUN2VfCGMlMwZRuELRkoFCbHS7ewl9YM160gTEYK7LYLqq14Kj6E9n8sieFdjRWDSGAWQagee4wLKBOgZdM5Cg7AWT44eCYTONeas+psMg0/o6toNHvYSgEjhi3bgJlMJVnTD+epL3mJh6HSmyhYjpL/0JHJGhj1sJM36EiZblI2OhKH210C+nEXFHGSofFHGlYebPragok3Eb/tAL1kBOkhdoregiXGrm3UoRt0yfWdQL0mfRTET0tQtOSkbN2kgXnh1Ua+qPo9qd/RYst2NTIfkNKpD5EFrmqzlVaSGS87YfIYPMeR3QnCQBJ3GgJfgxU+RVhQ1cdxZGMr26jLLWBhOxZgAQA7v9ZQPqzGwOIUVss7RDitUeLAZCW8DyuyjEdE+BKwYrxD2SG1grg0uK2OCpDDpTOCdOcINa0f+nlnFKY0yUKGulsnXnuEpBuY05uwWfchK4fYSPK9uF07b7E1GnMFq60YDBz5AeYSr/H0LW/RaTujDhK23vPnP/3fNbfHE6b111ugibUJqunQn0SrUq0ZhjtdtEOpreC66gjR6uuAL7XbUGmqXOKJAJ311ZnlreK1z2EcuiyMc/Sw7mDFNgSKfLmbDN4mg5bGZ79YKq+z5Jhr2RJxzXaYKs9RtWf6EKE19QOe4+mGI8OcaStmVkWEyZDi5DIH3ZK8ANoGYIqiFBQ4w/PFjSmnRgqH6c9U209+IrIGzKM/r6X0bnEO2dynpx9DK6bPzRkcRB/bhtgyDQIc3zt0/lWiSmxrihLTCkmVC8yrWp168gn/Yy/cld39yWBawXd8xwD81aFq8GgD7o+s7gZGzdmBX4sZEK0eiwbQdrtnARuPpheWar5F8SfTX0wtlX/Iyp9u/YAsAfvjSOh1ra2p6Eo9J56NFvxi3va5tjU8woG0kQDoCylc1qbbi9FmenMQFbDjofOUdK12t1OjmW+HQmwL+hqjqBtslMvUiKdZiYiecf+VXKA6DPi79WL+F3rHHf2/oyjt9v/2ouQe//Vn+SCCyANO8JtIbe3BkfMAYZkQl+uBZEz4neJm/IPO7JoI+tW4Ai8974j+73/ylWL2ZkHIjHjZxa+P3SBO+Jd1PWsmVHMGXPwB5vDe1PQDQaPRyYRv40h/t4Y/GdbsRwky9gCjoPjgw/L9jFrcutyRA08XJSpqPLIH67cCX42DzYSXlKVowjwVeSUyr4nyUnh5GgUiKys/83K/zJPSq8sCfktCPw+qpqxFlsdJ6lvPBD1vUiDcEzzXT4NU/4JeRz2HKKOvfxoNDF4CpIFON5vIZoUTVOvQ2Du8rvrmUKVxFomqiesizxI4X3lTxk2YVWWUe1EQFE0QVnXoizqNa7+oijCLgyQuk8wPgsqPh+YAR7V/DuHuORx/c/r88mJgsFkVellTpk2SpaKKw9rPhCjKPC6Lwk9jEWVR7BVZ0dSxFxQBLHLQeKKpcrjEq/xwYLCRFwT9g82inYO1Y4V94w3DuMzSIIozpIUkb6o0iZO88OoC1rmBRQrKpEmKKKqboBBxVqd+VAdeKgq/8fJsaHH9eGBxgzvG+/T41cnpwGCTtIn9UNRhkjVZ7Aee38BiJk0aBk0URSKJsiIUeeSVIkj8yPfrqijKqMwbXxRBMLS4fpINUcIdg0W8t7PHry7Png+tb+IneVbmeeKnRVFVYSOK0I+9MPKzHPY8ScskSssmFiKuyzyNE6CEJmlEnsepXyfe0JDjJBk4gOHOIZ+fHp88G1rfvArjuKiToMiLJi6yOvdEUjQi8KKqiDxRwLdNFVR56KUpUI7nAyPIs7CMkjiOknKIeIHbDBCvv3OwFqpM33CjoikKkKNZFAV5BBvcNHmWBQHse+2JOAVGUCdhCpI3wzUG+yzL/KzIgzQB6qmLQcaQ+wPkEOwcLoUYQU+dKBzAIR5RBqEIsiQPsyKto6iM6yTPURkoAjh0dVTBSkd53kQpsDnY6chLyyIMoqqqUj8dook8iMOBM5elewz8/Mmvzy5Pn1y+Oh+ijyaqwzwPkyRMqiirK6+KKr8MgBHABTAhr6h90fgwhayuy6BCflwBj85LYIqJ3wwNHLjbwMBj7+6Bt8AQenkc0G3txR7IOjhxXuQlsR81TShgApkI0rAqs6jIvDJMUziWQOFhE5QoKr1K+J4YPIO+N0AosRfdPe52ll3fwP0yDeIsCLMsrhovgXlEYZVVOVBIBksOO5AUeQ08MMiLIk9LkJFgMjVpXaYwJa8aGDiciAFCgSndPe6X5yeDws9LozRNRFRWoF4AV6hE3YDUTmO/bIBbg3RpmrLwRRgAB6/qWgApBXUKakqRDTI7ONFDBAK0uM+Az357/GRokb04BwJM6jQKRZOWcQJyJQNNCaS3F5epF9Ug9eKyLkD9iHwQMxWMBzUSuKD2vGhg0Anw94FFjvZY5PMXwKePXw4RhvA84YPAzrIm9zIwaWFcufBjEIRhHIQ+8I0QiCDy46ZBmZkkAXDLPPWA+yVlOjBmlEofpWV0McB61Tg4STVIuFSkQRgWeVmnYS2EF2ZNGudhDstaiSj1clEmFfDF2k+AFYKKBCpdAqxvYMwZUPzAOqf7DPryxfn/ePzieJCmy7wOqjADjQJ2O4gEjDUXTd00qQ8bkBZ1kAZAHCVQji9AtU5gQhEITZhiJcI8GKLpNI0HBLi/96hf/GZyBpbKc/xrYPg1nJ26Sj1Q2ANgz01YZEHcBEESAZtugriqEuDVkR9UMVzReHVcgWIVAjusRdTUQwZAEA7pd3l+9/AvTy8uJxcgIi9PvxkaOFgjQLJpUwexDwITmF7gRxkMNm3gyxD4dAn6PygiwF5AgQULoIxBMcmbLChhg4Z4SRoOsRIQrHuM/NegQF3ulDZ+VfpeVfhV3BSeCFFbjssqBSUQLIAaxCFoUqACgmYaAhsE0krLoIjBxslBnAD3HmTa0RDT3kctuRwkcD8EWg2CGNhG3qR5DZpdAQzFQ9XPz0H3i4Fvg/kCFASqt1cHERB5BGo4aFfCa4aUPj8CUTCkVe8x4FfPhhYYVDwR4uvhgKVRDjpJCqLaD+MiF2EF57AKQdjEUQVKHxxK5IV+WBdelOR+UnlD diff --git a/.bootstrap/payload.part09 b/.bootstrap/payload.part09 deleted file mode 100644 index 5f499bb..0000000 --- a/.bootstrap/payload.part09 +++ /dev/null @@ -1 +0,0 @@ -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 diff --git a/.cwl/data-management.yaml b/.cwl/data-management.yaml new file mode 100644 index 0000000..ffc929c --- /dev/null +++ b/.cwl/data-management.yaml @@ -0,0 +1,48 @@ +schema_version: '1.0' +repository: ContextualWisdomLab/ELUNVERA +product_name: ELUNVERA +authoritative_data_assets: + - asset_code: customer_relationship_record + description: Tenant-scoped parties, accounts, roles, relationships, evidence, and history. + data_classification: restricted_personal_and_commercial + system_of_record: true + - asset_code: commercial_opportunity_record + description: Opportunity process, stage, value, forecast, stakeholder, and outcome history. + data_classification: confidential_commercial + system_of_record: true + - asset_code: complaint_outcome_record + description: Complaint, remedy, customer response, satisfaction observation, and outcome history. + data_classification: restricted_customer_case + system_of_record: true +data_owner_role: elunvera_product_owner +data_steward_role: tenant_data_steward +critical_data_elements: + - party_identity_reference + - relationship_truth_status + - relationship_valid_time + - account_owner_assignment + - opportunity_stage_history + - monetary_amount_and_currency + - communication_preference + - complaint_status +quality_rule_references: + - docs/DATA_MODEL.md#18-data-quality-invariants + - docs/TEST_STRATEGY.md +retention_policy_references: + - docs/PRIVACY.md#8-retention-and-disposition + - docs/adr/0015-retention-disposition.md +lineage_producers: + - elunvera_api + - elunvera_worker +lineage_consumers: + - semantic_data_portal + - lineageweave +applicable_knowledge_areas: + - data_governance + - data_quality + - metadata_management + - data_security + - data_integration_and_interoperability +assessment_exclusions: + - code: production_runtime_evidence + reason: The repository baseline contains no implemented runtime. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..586f3cd --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,38 @@ +## Product outcome + +Describe the buyer- or operator-visible problem closed by this PR. + +## Scope and boundaries + +- Owning ELUNVERA responsibility: +- CWL dependencies consumed by contract: +- Explicitly excluded work: + +## Evidence + +- Exact head: +- Tests and commands actually run: +- Coverage and documentation denominators: +- Migration/restore/security/accessibility/model evidence, where applicable: + +## Data and privacy + +- Data assets and classifications changed: +- Tenant, purpose, retention, legal-hold, and export impacts: +- New event fields reviewed for PII/secrets: + +## Contracts and docs + +- [ ] OpenAPI/AsyncAPI/JSON Schema updated +- [ ] ADR updated or decision remains conformant +- [ ] `docs/product-technical-gap-baseline.md` updated +- [ ] `CHANGELOG.md` updated +- [ ] Doctoring and references updated + +## Review gate + +- [ ] Current-head checks complete +- [ ] Independent approval received +- [ ] Unresolved threads are zero +- [ ] No queued/pending/skipped check is represented as successful +- [ ] One-shot/self-modifying workflow removed after its purpose diff --git a/.github/workflows/bootstrap-baseline.yml b/.github/workflows/bootstrap-baseline.yml deleted file mode 100644 index 1a3ef48..0000000 --- a/.github/workflows/bootstrap-baseline.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: Bootstrap ELUNVERA documentation baseline - -on: - push: - branches: - - docs/product-technical-baseline - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: elunvera-bootstrap-baseline - cancel-in-progress: false - -jobs: - bootstrap: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out the exact feature branch - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - ref: docs/product-technical-baseline - fetch-depth: 0 - - - name: Reconstruct, verify, and materialize the baseline - shell: bash - run: | - set -euo pipefail - cat .bootstrap/payload.part* | tr -d '\n\r\t ' | base64 --decode > /tmp/elunvera-baseline.tar.gz - echo "3d5ea6633df9edd20722a19f77ffbd9f4d88da462a561341363273dc405eb551 /tmp/elunvera-baseline.tar.gz" | sha256sum --check - - test "$(tar -tzf /tmp/elunvera-baseline.tar.gz | wc -l)" -eq 55 - tar -xzf /tmp/elunvera-baseline.tar.gz -C . - rm -rf .bootstrap - rm -f .github/workflows/bootstrap-baseline.yml - rm -f .github/workflows/permission-probe.yml - python - <<'PY' - import hashlib - import json - from pathlib import Path - - manifest = json.loads(Path("manifest.json").read_text(encoding="utf-8")) - entries = manifest["files"] - assert manifest["file_count"] == len(entries) == 54 - for entry in entries: - path = Path(entry["path"]) - assert path.is_file(), f"missing manifest file: {path}" - payload = path.read_bytes() - assert len(payload) == entry["size_bytes"], f"size mismatch: {path}" - assert hashlib.sha256(payload).hexdigest() == entry["sha256"], f"hash mismatch: {path}" - - for path in ( - "schemas/events/opportunity-stage-changed-v1.schema.json", - "schemas/events/relationship-changed-v1.schema.json", - ): - json.loads(Path(path).read_text(encoding="utf-8")) - - required = ( - "docs/PRD.md", - "docs/TRD.md", - "docs/ARCHITECTURE.md", - "docs/DATA_MODEL.md", - "docs/API_CONTRACT.md", - "docs/product-technical-gap-baseline.md", - "docs/adr/README.md", - "schemas/openapi.yaml", - "schemas/asyncapi.yaml", - ) - missing = [path for path in required if not Path(path).is_file()] - assert not missing, f"missing required files: {missing}" - PY - test ! -e .bootstrap - test ! -e .github/workflows/bootstrap-baseline.yml - test ! -e .github/workflows/permission-probe.yml - - - name: Commit the verified documentation baseline - shell: bash - run: | - set -euo pipefail - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - test "$(git ls-files --cached | wc -l)" -eq 55 - git commit -m "docs: establish ELUNVERA product and technical baseline" - git push origin HEAD:docs/product-technical-baseline diff --git a/.github/workflows/permission-probe.yml b/.github/workflows/permission-probe.yml deleted file mode 100644 index 05751b4..0000000 --- a/.github/workflows/permission-probe.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: Permission probe - -on: - workflow_dispatch: - -permissions: - contents: read - -jobs: - probe: - runs-on: ubuntu-latest - steps: - - run: echo "workflow path write permission confirmed" diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..3b232f1 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,84 @@ +# AGENTS.md — ELUNVERA + +## Required reading order + +Before changing this repository, read: + +1. `README.md` +2. `docs/PRD.md` +3. `docs/TRD.md` +4. `docs/ARCHITECTURE.md` +5. `docs/DATA_MODEL.md` +6. `docs/product-technical-gap-baseline.md` +7. `docs/adr/README.md` +8. the relevant ADRs and doctoring material +9. the current pull request, exact head, checks, reviews, and unresolved threads + +The repository and current GitHub state are the source of truth. Private memory and prior chat summaries are not. + +## Product responsibility + +ELUNVERA is the authoritative system for tenant-scoped customer relationship and commercial opportunity facts. It must not absorb capabilities owned by another ContextualWisdomLab product. + +Never turn ELUNVERA into: + +- an email or calendar host; +- an ERP, CPQ, accounting, payment, or subscription ledger; +- an HRIS; +- a generic issue tracker or project manager; +- an ontology catalog; +- an autonomous agent that changes customer or opportunity facts without policy and human authority. + +## Data and naming rules + +- Database objects use `snake_case` and at least two words. +- Every tenant-owned row has an enforced tenant boundary. +- Temporal facts preserve business-valid time and system-recorded time. +- Relationships are first-class facts with evidence, provenance, confidence, and validity. +- External IDs are references, never internal primary keys. +- Provider payloads do not define canonical domain state. +- Raw PII is not broadcast through events or model traces. +- Ingestion uses item-level idempotency and records an immutable receipt. +- Hard delete is forbidden for audit, stage history, relationship history, model evidence, and legal-hold material. + +## Engineering rules + +- Use Rust for the API, domain services, high-throughput ingestion, security-sensitive logic, graph computations, vector operations, statistics, and model calculations. +- TypeScript may implement the web interface and generated clients. +- Python is permitted for non-production validation, research comparison, or connector glue only when no production numerical logic is introduced. +- Do not suppress deprecation warnings. Fix the cause. +- Do not introduce arbitrary weights, hard-coded “health scores,” stage-derived probabilities, or rule-of-thumb forecasts. +- All AI results are proposals or evidence-linked assessments until an authorized workflow accepts them. +- Do not send customer source content directly to a model provider outside `contextual-orchestrator` contracts. +- Do not mix unrelated dependency or refactoring changes into a product slice. + +## Test and documentation gates + +For ELUNVERA-owned production code: + +- statement coverage: 100%; +- branch coverage: 100%; +- public module/type/trait/function/method documentation: 100%; +- property and fuzz tests for parser, identifier, temporal, money, and authorization boundaries; +- real PostgreSQL integration tests; +- tenant-isolation and purpose-authorization tests; +- migration clean-install, upgrade, rollback, and restoration rehearsals; +- CPU/GPU parity and true-parameter recovery for any numerical model; +- no skipped or ignored required GPU lane; +- accessibility, keyboard, responsive, print/export, and internationalization tests for user interfaces. + +Update `CHANGELOG.md`, `docs/product-technical-gap-baseline.md`, affected ADRs, contracts, and doctoring traceability in the same pull request. + +## Pull request operation + +Use `develop` as the base branch unless an explicitly approved stack requires another feature branch. + +Before commit or push: + +1. re-read remote branch and pull-request state; +2. preserve concurrent agent changes and understand their intent; +3. remove one-shot or self-modifying workflows after their bounded purpose; +4. run the exact validation commands claimed in the pull request; +5. record actual evidence, not anticipated results. + +Never claim a check passed if it is queued, pending, skipped, or was run on an older head. Never force-push over another agent’s work merely because the branch changed. diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..30ba533 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,24 @@ +# Changelog + +All notable changes to ELUNVERA will be documented in this file. + +The format follows Keep a Changelog principles, and versioning will begin when the first executable release candidate exists. + +## [Unreleased] + +### Added + +- Initial ELUNVERA product and technical documentation baseline. +- Product requirements, technical requirements, architecture, data model, API and event contracts. +- Security, privacy, threat-model, testing, operability, UX, user-story, use-case, storyboard, wireframe, and Storybook baselines. +- Architecture decision record set covering product ownership, modularity, identity, tenancy, temporal facts, relationships, integrations, privacy, AI, persistence, APIs, quality, UX, retention, and ecosystem boundaries. +- OpenAPI 3.2.0 and AsyncAPI 3.1.0 draft contracts. +- Initial product-technical gap baseline and phased implementation plan. + +### Security + +- Defined fail-closed tenant isolation, purpose-aware authorization, immutable audit, model provenance, controlled egress, and customer-data disclosure boundaries. + +### Notes + +- No runtime, database schema, deployment artifact, or release exists in this baseline. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..c0be734 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,34 @@ +# CLAUDE.md — ELUNVERA repository context + +ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence system of record. + +## North-star behavior + +Turn scattered customer context into a judgment-ready structure and an evidence-linked next action. Do not produce generic summaries or opaque scores. + +## Canonical boundaries + +- Keyverse owns identity and federation. +- naruon owns interaction with customer-controlled email, calendar, and files. +- ThreadWeave computes email threads. +- LineageWeave proposes inferred lineage. +- ScopeWeave owns generalized work and project execution. +- Billing Control Plane owns commercial metering, entitlement, invoices, and payment truth. +- Semantic Data Portal owns cross-product ontology and catalog context. +- ELUNVERA owns customer relationship, commercial account, opportunity, commitment, complaint, and customer-outcome facts. + +## Non-negotiable implementation constraints + +- Rust-first backend and compute boundary. +- PostgreSQL 18.6+ within supported 18.x. +- 3NF canonical store; graph/search/vector views are projections. +- Tenant isolation enforced in application and database layers. +- Purpose-aware access and field selection; no destructive masking of authorized operational data. +- Bitemporal relationship and role history. +- Exact decimal money; no binary floating-point monetary calculations. +- No heuristic relationship-health or forecast weights. +- Human authority for irreversible customer-facing actions. +- Full provenance for model-generated claims. +- 100% production statement/branch/doc coverage for ELUNVERA-owned shipped code. + +Read `AGENTS.md` and the product/technical documents before making changes. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..79fc2d9 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,43 @@ +# Contributing to ELUNVERA + +## Branching + +- Base product work on `develop`. +- Use bounded branches such as `docs/product-technical-baseline`, `feat/account-registry`, or `fix/tenant-authorization`. +- One pull request should deliver one independently reviewable product or platform slice. + +## Before opening a pull request + +1. Rebase or merge the current approved base without rewriting other agents’ work. +2. Run all repository validation commands relevant to the changed files. +3. Update contracts, tests, documentation, ADRs, the changelog, and the product-gap baseline together. +4. State what was actually verified and what remains unverified. +5. Do not add generated artifacts without deterministic generation and source files. + +## Design expectations + +New product behavior requires: + +- a user and buyer problem; +- an owning module or repository; +- a data and authorization contract; +- failure and rollback behavior; +- test evidence; +- operability and security impact; +- an ADR when the change alters a durable architectural decision. + +## Commit messages + +Use conventional prefixes such as: + +- `docs:` documentation and contract baselines; +- `feat:` buyer-visible behavior; +- `fix:` defect correction; +- `refactor:` behavior-preserving structure change; +- `test:` test-only change; +- `ci:` workflow and build policy; +- `security:` security-boundary hardening. + +## Review standard + +A reviewer must be able to trace every important claim from requirement to contract, implementation, and test. A document existing is not evidence that the product implements it. diff --git a/README.md b/README.md index 644a408..24b2ba3 100644 --- a/README.md +++ b/README.md @@ -2,4 +2,80 @@ > **Every Link, Understood. Every Relationship, Activated.** -ELUNVERA is a ContextualWisdomLab CRM initiative. Product and technical baselines are introduced through pull requests targeting `develop`. +ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence platform. It gives customer-facing teams a governed system of record for commercial accounts, stakeholders, interactions, commitments, opportunities, customer outcomes, and the decisions that connect them. + +ELUNVERA is not an email host, a calendar server, an ERP, a billing engine, a project-management suite, or an autonomous sales agent. It composes those capabilities through explicit ContextualWisdomLab contracts while preserving a narrow source-of-truth boundary. + +## Product promise + +ELUNVERA helps a user answer four questions without reconstructing context manually: + +1. **What changed in this relationship?** +2. **Why does it matter now?** +3. **What commitment or decision is at risk?** +4. **What is the next defensible action, and what evidence supports it?** + +## Initial product boundary + +ELUNVERA owns: + +- tenant-scoped commercial accounts and account-role history; +- people, organizations, contact points, and time-valid relationship facts; +- account-team assignments; +- interaction and evidence references; +- commitments and relationship actions; +- opportunities, stage history, stakeholder participation, values, and forecast snapshots; +- customer outcomes, complaints, satisfaction observations, and relationship assessments; +- purpose, communication preference, retention, audit, and data-rights workflow metadata. + +ELUNVERA consumes but does not own: + +- identity and federation from **Keyverse**; +- customer-owned email, calendar, and file interaction from **naruon**; +- RFC email threading from **ThreadWeave**; +- inferred record lineage from **LineageWeave**; +- retrieval fusion from **RankWeave**; +- LLM routing and evaluation from **contextual-orchestrator**; +- temporal measurement from **TEPP** and psychometric calibration from **fast-mlsirm**; +- ontology and catalog context from **semantic-data-portal**; +- generalized project and issue execution from **ScopeWeave**; +- commercial entitlement and billing truth from **billing-control-plane**. + +## Documentation map + +| Document | Purpose | +|---|---| +| [`docs/PRD.md`](docs/PRD.md) | Product vision, users, requirements, scope, and release criteria | +| [`docs/TRD.md`](docs/TRD.md) | Technical requirements and platform constraints | +| [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) | System boundaries, components, trust zones, and deployment model | +| [`docs/DATA_MODEL.md`](docs/DATA_MODEL.md) | Canonical entities, temporal facts, ERD, and data invariants | +| [`docs/API_CONTRACT.md`](docs/API_CONTRACT.md) | HTTP, event, idempotency, pagination, and compatibility contracts | +| [`docs/SECURITY.md`](docs/SECURITY.md) | Security architecture and control baseline | +| [`docs/PRIVACY.md`](docs/PRIVACY.md) | Purpose limitation, data rights, retention, and disclosure rules | +| [`docs/THREAT_MODEL.md`](docs/THREAT_MODEL.md) | Assets, actors, abuse cases, and mitigations | +| [`docs/TEST_STRATEGY.md`](docs/TEST_STRATEGY.md) | TDD, coverage, contract, security, and realistic validation | +| [`docs/OPERABILITY.md`](docs/OPERABILITY.md) | SLOs, telemetry, backup, restoration, and incident response | +| [`docs/UX_SPEC.md`](docs/UX_SPEC.md) | Customer-facing information architecture and interaction principles | +| [`docs/product-technical-gap-baseline.md`](docs/product-technical-gap-baseline.md) | Current implementation truth and prioritized gaps | +| [`docs/adr/README.md`](docs/adr/README.md) | Architecture decision index | +| [`docs/doctoring/REFERENCES.md`](docs/doctoring/REFERENCES.md) | APA 7th research and standards bibliography | + +## Development status + +This repository currently contains a **documentation and contract baseline only**. No production service, database migration, UI, connector, benchmark result, certification, or release claim exists yet. The implementation sequence is defined in [`docs/ROADMAP.md`](docs/ROADMAP.md) and the executable plan in [`docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md`](docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md). + +## Working conventions + +- Primary integration branch: `develop` +- Review flow: feature branch → current-head checks → independent review → squash merge +- Database object names: two or more words in `snake_case` +- Production arithmetic and model computation: Rust +- API source: OpenAPI 3.2.0 +- Event source: AsyncAPI 3.1.0 with CloudEvents 1.0 envelopes +- Database baseline: PostgreSQL 18.6 or later supported 18.x security release +- Accessibility target: WCAG 2.2 AA +- Quality target for shipped ELUNVERA-owned code: 100% production statement coverage, 100% production branch coverage, and 100% public API documentation coverage + +## License + +No software license is asserted by this documentation-only baseline. A repository license decision must be recorded before distributable source code is accepted. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..542afc7 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,32 @@ +# Security policy + +## Current status + +ELUNVERA does not yet have a released runtime. Security reports concerning future design material may be filed as private GitHub security advisories when that facility is enabled. Do not disclose real customer data, credentials, or proprietary evidence in a public issue. + +## Future supported versions + +No supported software version exists. This table will be populated at the first release candidate. + +## Security design baseline + +The normative security design is in: + +- `docs/SECURITY.md` +- `docs/PRIVACY.md` +- `docs/THREAT_MODEL.md` +- `docs/adr/0003-keyverse-identity.md` +- `docs/adr/0007-purpose-aware-privacy.md` +- `docs/adr/0012-quality-release-gates.md` + +## Disclosure rules + +A valid report should include: + +- affected contract, component, or future version; +- reproduction conditions without real personal data; +- expected and observed authorization boundary; +- potential confidentiality, integrity, availability, privacy, financial, or safety impact; +- mitigations already attempted. + +Do not test against systems or data without authorization. diff --git a/docs/API_CONTRACT.md b/docs/API_CONTRACT.md new file mode 100644 index 0000000..bae3001 --- /dev/null +++ b/docs/API_CONTRACT.md @@ -0,0 +1,287 @@ +# ELUNVERA API and Event Contract + +- **Document version:** 0.1 +- **Status:** Proposed contract baseline +- **Date:** 2026-08-27 + +## 1. Contract objectives + +ELUNVERA exposes versioned HTTP and event contracts that preserve tenant isolation, temporal truth, idempotency, provenance, and provider independence. The contracts describe target behavior; no endpoint is implemented by this documentation baseline. + +## 2. Contract sources + +- HTTP source: `schemas/openapi.yaml`, OpenAPI 3.2.0. +- Event source: `schemas/asyncapi.yaml`, AsyncAPI 3.1.0. +- Payload schemas: JSON Schema Draft 2020-12 under `schemas/events/`. +- Error representation: RFC 9457 Problem Details. +- Event envelope: CloudEvents 1.0. + +Generated SDKs may be published only from a tagged, validated contract revision. Hand-maintained clients are not authoritative. + +## 3. Authentication and request context + +Every authenticated request carries a Keyverse-issued bearer token. The API validates issuer, audience, signature, token type, time bounds, and required claims before constructing this immutable context: + +```text +actor_reference +principal_kind_code +tenant_reference +workspace_reference +role_set +scope_set +purpose_code +decision_reference +correlation_id +authentication_strength +token_issued_at +token_expires_at +``` + +A caller-supplied `tenant_id`, role, purpose, or actor header never overrides verified claims. Service-to-service calls use a service principal and an explicit delegated purpose. + +## 4. Common HTTP rules + +### 4.1 Base and media types + +- Base path: `/v1`. +- Default request and response media type: `application/json`. +- Export formats use explicit versioned media types. +- UTF-8 is mandatory. +- Unknown top-level fields are rejected for commands unless the schema explicitly permits extensions. + +### 4.2 Request identity + +Mutating operations require: + +```http +Idempotency-Key: 019d4b72-507c-71a8-9026-1b82067f40f1 +X-Correlation-Id: 019d4b72-507c-71a8-9026-1b82067f40f2 +``` + +The server stores the key, canonical request hash, operation status, response reference, and expiration policy. Replaying the same key with the same canonical payload returns the original receipt. Reusing the key with a different payload returns `409 Conflict`. + +### 4.3 Concurrency + +Editable aggregates return an ETag. A command that changes an existing aggregate requires `If-Match`. A stale version returns `412 Precondition Failed` and does not apply a partial change. + +### 4.4 Pagination + +Collection endpoints use opaque cursor pagination: + +```json +{ + "items": [], + "next_cursor": "opaque-value-or-null", + "page_size": 50 +} +``` + +Ordering is deterministic. A cursor binds the tenant, filter, sort, and knowledge cutoff. Page size is bounded by the contract. + +### 4.5 Time and knowledge cutoff + +Temporal reads may specify `valid_at`, `recorded_at`, or `knowledge_cutoff`. The response echoes the effective temporal lens. The server does not use facts recorded after the requested knowledge cutoff. + +### 4.6 Long-running operations + +Imports, exports, bulk merges, model evaluations, and large relationship projections return `202 Accepted` with a durable `job_reference`. Job states are: + +```text +accepted → queued → running → succeeded + ├→ failed + └→ cancellation_requested → cancelled | succeeded +``` + +The cancellation receipt states whether execution stopped before work, during work, or after completion. + +## 5. Problem Details + +Every non-success response uses RFC 9457 fields and ELUNVERA extensions: + +```json +{ + "type": "urn:elunvera:problem:stale-aggregate", + "title": "The record changed before this update was applied.", + "status": 412, + "detail": "Refresh the account and review the latest changes before saving again.", + "instance": "urn:elunvera:operation:019d...", + "error_code": "stale_aggregate", + "correlation_id": "019d...", + "safe_next_action": "refresh_and_compare" +} +``` + +Messages help the user take the next action and never expose SQL, internal service names, stack traces, secrets, or cross-tenant existence. + +## 6. Resource endpoints + +The initial contract surface is deliberately narrow. + +### Accounts + +```text +POST /v1/accounts +GET /v1/accounts/{account_id} +PATCH /v1/accounts/{account_id} +GET /v1/accounts +GET /v1/accounts/{account_id}/timeline +GET /v1/accounts/{account_id}/relationships +POST /v1/accounts/{account_id}/merge-jobs +POST /v1/accounts/{account_id}/split-jobs +``` + +### Parties and relationships + +```text +POST /v1/parties +GET /v1/parties/{party_id} +PATCH /v1/parties/{party_id} +POST /v1/relationships +GET /v1/relationships/{relationship_id} +PATCH /v1/relationships/{relationship_id} +POST /v1/relationships/{relationship_id}/review-decisions +``` + +### Interactions and commitments + +```text +POST /v1/interactions +GET /v1/interactions/{interaction_id} +POST /v1/commitments +PATCH /v1/commitments/{commitment_id} +POST /v1/commitments/{commitment_id}/transitions +``` + +### Opportunities + +```text +POST /v1/opportunities +GET /v1/opportunities/{opportunity_id} +PATCH /v1/opportunities/{opportunity_id} +POST /v1/opportunities/{opportunity_id}/stage-transitions +POST /v1/opportunities/{opportunity_id}/value-snapshots +POST /v1/opportunities/{opportunity_id}/forecast-snapshots +``` + +### Customer outcomes and complaints + +```text +POST /v1/customer-outcomes +GET /v1/customer-outcomes/{outcome_id} +POST /v1/complaints +GET /v1/complaints/{complaint_id} +POST /v1/complaints/{complaint_id}/transitions +POST /v1/satisfaction-observations +``` + +### Search and proposed intelligence + +```text +POST /v1/search-queries +POST /v1/context-bundles +POST /v1/model-jobs +GET /v1/model-jobs/{job_id} +POST /v1/model-claims/{claim_id}/review-decisions +``` + +Model endpoints return evidence references, uncertainty, model identity, prompt hash, and review status. A model claim cannot mutate authoritative CRM facts. + +### Privacy and audit + +```text +POST /v1/data-rights-cases +GET /v1/data-rights-cases/{case_id} +POST /v1/data-rights-cases/{case_id}/exports +POST /v1/disposition-jobs +POST /v1/legal-holds +GET /v1/audit-events +``` + +Audit search is purpose-restricted and paginated. Export manifests identify included and excluded fields, source authority, and policy reason. + +## 7. Command receipts + +A successful mutation returns a stable receipt rather than relying only on an HTTP status: + +```json +{ + "operation_id": "019d...", + "aggregate_reference": "urn:elunvera:tenant:account:019d...", + "aggregate_version": 7, + "recorded_at": "2026-08-27T09:00:00Z", + "event_reference": "urn:elunvera:event:019d...", + "idempotency_status": "new" +} +``` + +Receipts are queryable and included in audit evidence. + +## 8. Event envelope + +Domain events include the CloudEvents core fields plus bounded extensions: + +```json +{ + "specversion": "1.0", + "id": "019d...", + "source": "urn:elunvera:tenant_001", + "type": "org.contextualwisdomlab.elunvera.relationship.changed.v1", + "subject": "urn:elunvera:tenant_001:relationship:019d...", + "time": "2026-08-27T09:00:00Z", + "datacontenttype": "application/json", + "tenantref": "urn:elunvera:tenant_001", + "correlationid": "019d...", + "causationid": "019d...", + "provenanceref": "urn:elunvera:evidence:019d...", + "purposecode": "account_management", + "data": {} +} +``` + +Events never contain passwords, tokens, raw email bodies, unrestricted notes, unnecessary contact details, or provider secrets. + +## 9. Initial event types + +```text +account.created.v1 +account.changed.v1 +account.merged.v1 +account.split.v1 +party.changed.v1 +relationship.changed.v1 +relationship.reviewed.v1 +interaction.recorded.v1 +commitment.changed.v1 +opportunity.changed.v1 +opportunity.stage_changed.v1 +forecast_snapshot.recorded.v1 +complaint.changed.v1 +satisfaction_observation.recorded.v1 +model_claim.proposed.v1 +model_claim.reviewed.v1 +data_rights_case.changed.v1 +disposition.completed.v1 +``` + +An event type is immutable. A breaking payload change creates a new major suffix. + +## 10. Consumer rules + +- Delivery is at least once. +- Consumers deduplicate by `(source, id)` and persist an inbox receipt. +- Consumers validate schema before applying a projection. +- Processing and its projection receipt commit atomically. +- Poison messages move to a dead-letter workflow without blocking unrelated tenant events. +- A consumer never upgrades `inferred` or `proposed` truth to `authoritative` automatically. + +## 11. Provider adapters + +Integrations use capability-specific ports such as `interaction_observation_port`, `calendar_commitment_port`, `identity_resolution_port`, `billing_entitlement_port`, and `work_execution_port`. Core tables do not acquire columns such as `salesforce_id`, `hubspot_id`, or `stripe_customer_id`; mappings live in `external_object_mapping`. + +## 12. Compatibility policy + +- Additive optional fields require a minor contract version. +- Removing a field, tightening an enum, or changing semantics requires a new major API or event version. +- A deprecated field remains supported for at least two minor releases and one documented migration window. +- Schema changes include positive, negative, and backward-compatibility fixtures. +- Provider and consumer contract tests run in both owning repositories. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000..e4c1424 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,250 @@ +# ELUNVERA Architecture + +## 1. Architecture purpose + +This document defines ELUNVERA’s durable responsibility boundaries and deployable shape. It prevents a CRM repository from absorbing email hosting, project management, billing, identity, ontology, or scientific-compute responsibilities that already belong elsewhere in the CWL ecosystem. + +## 2. Context diagram + +```mermaid +flowchart LR + U[Customer-facing user] --> W[ELUNVERA Web] + W --> A[ELUNVERA API] + A --> P[(PostgreSQL 18.6+)] + A --> J[Durable Worker] + A --> O[Transactional Outbox] + + K[Keyverse] -->|OIDC / SCIM| A + N[naruon] -->|interaction metadata and source refs| A + TW[ThreadWeave] -->|thread structure| N + LW[LineageWeave] -->|inferred lineage proposals| A + RW[RankWeave] -->|retrieval fusion| A + CO[contextual-orchestrator] -->|schema-bound AI results| A + SDP[Semantic Data Portal] <-->|ontology and catalog refs| A + SW[ScopeWeave] <-->|work-item refs| A + BCP[Billing Control Plane] -->|entitlement refs| A + TEPP[TEPP / fast-mlsirm] -->|validated model artifacts| A + A --> OT[OpenTelemetry Collector] +``` + +## 3. Source-of-truth matrix + +| Fact | Authority | +|---|---| +| Commercial account, customer/prospect/partner role history | ELUNVERA | +| Contact and organization relationship facts inside a tenant | ELUNVERA | +| Opportunity, stage, stakeholder, value, forecast snapshot | ELUNVERA | +| Customer commitment, complaint, outcome, satisfaction reference | ELUNVERA | +| User authentication, federation, SCIM identity | Keyverse | +| Raw mailbox, calendar, and file content | Customer provider / naruon control plane | +| RFC message thread computation | ThreadWeave | +| Generalized project and work execution | ScopeWeave | +| Invoice, subscription, payment, entitlement commercial truth | Billing Control Plane | +| Enterprise ontology and catalog | Semantic Data Portal | +| Inferred lineage proposal | LineageWeave | +| Model routing and LLM workflow trace | contextual-orchestrator | +| Psychometric and temporal analysis artifact | Psychometrics Commons, fast-mlsirm, or TEPP as applicable | +| Employee and employment truth | Orgmetra | + +## 4. Recommended approach + +### Approach A — Full-suite CRM monolith + +Place mail, calendar, tasks, marketing, billing, support, AI, and analytics in ELUNVERA. + +**Rejected:** duplicates established CWL products, creates excessive privileges, and makes customer data migration and release independence difficult. + +### Approach B — Graph-only intelligence overlay + +Leave all customer and opportunity truth in external CRMs and provide only an intelligence graph. + +**Rejected as the primary product:** useful as an integration mode, but it cannot guarantee authoritative relationship history, purpose policy, or reversible data stewardship. + +### Approach C — Federated CRM system of record with evidence and intelligence + +ELUNVERA owns the narrow commercial relationship and opportunity domain, while integrating with independent CWL systems through versioned ports. + +**Accepted:** preserves authority, modularity, auditability, and an incremental commercial path. + +## 5. Runtime topology + +### Initial deployment + +```text +reverse proxy / gateway + | + +-- elunvera_web + +-- elunvera_api + +-- elunvera_worker + +-- PostgreSQL + +-- object storage adapter + +-- OpenTelemetry collector +``` + +The API and worker may share one Rust workspace and deploy separately from the same versioned artifact. A dedicated message broker is optional at first; the transactional outbox and bounded polling worker provide durability without requiring a distributed control plane. + +### Extraction criteria + +A module may become an independent service only when at least one is demonstrated: + +- independent data authority; +- independent regulatory or security zone; +- materially different availability or scaling requirement; +- independent release ownership; +- workload isolation that cannot be achieved safely in-process; +- reuse by multiple products through a stable public contract. + +## 6. Internal component diagram + +```mermaid +flowchart TB + API[HTTP / Event Adapters] --> AUTH[Authorization Context] + API --> APP[Application Commands and Queries] + APP --> ACCT[Account Registry] + APP --> PARTY[Party Registry] + APP --> REL[Relationship Registry] + APP --> INT[Interaction Timeline] + APP --> COM[Commitment Registry] + APP --> OPP[Opportunity Management] + APP --> OUT[Customer Outcomes] + APP --> PRIV[Privacy Rights] + + ACCT --> REPO[Repository Ports] + PARTY --> REPO + REL --> REPO + INT --> REPO + COM --> REPO + OPP --> REPO + OUT --> REPO + PRIV --> REPO + + REPO --> PG[(PostgreSQL)] + APP --> AUDIT[Audit and Provenance] + APP --> OUTBOX[Transactional Outbox] + APP --> SEARCH[Search Projection] + APP --> INTEG[Integration Ports] +``` + +## 7. Command flow + +```mermaid +sequenceDiagram + participant User + participant Web + participant API + participant Auth as Authorization + participant Domain + participant DB as PostgreSQL + participant Outbox + + User->>Web: edit relationship fact + Web->>API: PATCH + If-Match + Idempotency-Key + API->>Auth: verify actor, tenant, purpose, fields + Auth-->>API: immutable context + API->>Domain: execute command + Domain->>DB: write new temporal version + Domain->>DB: append audit event + Domain->>Outbox: append domain event in same transaction + DB-->>API: committed aggregate version + API-->>Web: receipt + ETag +``` + +## 8. AI proposal flow + +```mermaid +sequenceDiagram + participant User + participant EL as ELUNVERA + participant CO as contextual-orchestrator + participant Source as Evidence Source + + User->>EL: request account brief + EL->>EL: authorize purpose and collect evidence refs + EL->>Source: fetch allowed evidence bundle + Source-->>EL: bounded evidence + EL->>CO: schema-bound task, untrusted evidence + CO-->>EL: claims, evidence refs, uncertainty, proposed actions + EL->>EL: validate schema, citations, access, and policy + EL-->>User: facts / inferences / unknowns / actions + User->>EL: accept, edit, or reject individual proposal +``` + +No AI output changes canonical state before the final user or approved policy action. + +## 9. Trust zones + +| Zone | Assets | Default trust | +|---|---|---| +| Browser | UI state, user input, rendered account data | Untrusted client | +| Public edge | HTTP headers, webhook payloads, uploaded files | Hostile input | +| Application | authorization context, domain commands | Trusted only after verification | +| Data store | canonical facts, audit, keys by reference | Restricted | +| Connector | provider tokens and external payloads | High-risk boundary | +| Model plane | prompts, evidence bundles, model output | Untrusted output and data processor | +| Observability | metrics, traces, logs | No raw customer content | +| Build/release | source, dependencies, artifacts, attestations | Supply-chain boundary | + +## 10. Data flows + +### Interaction observation + +```text +customer-owned source +→ naruon or approved connector +→ normalized interaction metadata +→ ELUNVERA source receipt +→ interaction projection +→ relationship / commitment proposal +→ human review +``` + +### Opportunity update + +```text +verified actor +→ opportunity command +→ optimistic concurrency +→ append stage/value/forecast fact +→ audit + outbox +→ read-model projection +``` + +### Data-rights export + +```text +verified request +→ identity and scope resolution +→ source inventory +→ purpose and legal-hold policy +→ asynchronous export +→ manifest + hashes + omissions/reasons +→ authorized download +→ expiry + audit receipt +``` + +## 11. Failure posture + +- Identity key unavailable: authenticated routes fail closed; liveness remains healthy and readiness fails. +- Database schema incompatible: startup fails closed. +- Outbox transport unavailable: canonical writes may continue only while bounded backlog and storage SLO remain safe; event lag alerts fire. +- AI provider unavailable: core CRM remains available; proposal workflow reports retryable unavailability. +- Search projection stale: exact canonical lookup remains available and UI labels search freshness. +- Connector failure: preserve last successful cursor and receipt; never mark incomplete sync as current. +- Authorization ambiguity: deny and record policy reason without leaking object existence. + +## 12. Deployment portability + +A Compose profile is the reference developer and single-node enterprise deployment. Services use health contracts and externalized configuration compatible with future Kubernetes deployment. Container project names remain stable outside isolated tests. GPU services, when introduced for model workloads, remain separately schedulable and are not required for the transactional CRM core. + +## 13. Architecture conformance + +The architecture is conformant when: + +- each canonical fact has exactly one declared authority; +- no integration uses direct cross-repository SQL; +- every projection can be rebuilt from authoritative records and receipts; +- all writes pass verified tenant and purpose context; +- model output is distinguishable from authoritative fact; +- every event has provenance and idempotent consumption; +- no user-facing workflow depends synchronously on an LLM; +- runtime and docs agree on implemented capabilities. diff --git a/docs/DATA_MODEL.md b/docs/DATA_MODEL.md new file mode 100644 index 0000000..cf8cbb3 --- /dev/null +++ b/docs/DATA_MODEL.md @@ -0,0 +1,504 @@ +# ELUNVERA Data Model + +## 1. Modeling goals + +The canonical model must preserve: + +- commercial account identity without equating an account to an organization forever; +- people, organizations, groups, and contact points without using mutable identifiers as primary keys; +- multiple simultaneous and time-varying roles; +- first-class relationships with evidence and disclosure policy; +- immutable stage, value, forecast, complaint, and commitment history; +- tenant isolation, bitemporal facts, provenance, and item-level idempotency; +- exact money and auditable model artifacts. + +## 2. Naming convention + +- Tables, columns, indexes, constraints, functions, and schemas use `snake_case`. +- Database object names contain at least two words. +- Primary keys use `_id` with UUIDv7 values. +- Foreign keys preserve the referenced object name. +- Boolean names express the affirmative condition. +- Timestamps use `_at`; business-valid ranges use `_valid_time`; system ranges use `_recorded_time`. +- Generic names such as `data`, `item`, `object`, `user`, `customer`, and `buyer` are not used without a bounded domain qualifier. + +## 3. Core ERD + +```mermaid +erDiagram + tenant_account ||--o{ workspace_record : contains + tenant_account ||--o{ party_record : owns + tenant_account ||--o{ commercial_account : owns + party_record ||--|| person_party : specializes + party_record ||--|| organization_party : specializes + party_record ||--|| group_party : specializes + + commercial_account }o--|| party_record : centers_on + commercial_account ||--o{ account_role_assignment : has + commercial_account ||--o{ account_team_assignment : staffed_by + workspace_member ||--o{ account_team_assignment : serves + + party_record ||--o{ contact_point_record : has + party_record ||--o{ relationship_participant : participates + relationship_record ||--o{ relationship_participant : contains + relationship_record ||--o{ evidence_reference : supported_by + + commercial_account ||--o{ interaction_record : contextualizes + interaction_record ||--o{ interaction_participant : includes + interaction_record ||--o{ commitment_record : yields + interaction_record ||--o{ evidence_reference : cites + + commercial_account ||--o{ opportunity_record : has + sales_process_version ||--o{ sales_stage_definition : defines + opportunity_record ||--o{ opportunity_stage_transition : changes + opportunity_record ||--o{ opportunity_party_role : includes + opportunity_record ||--o{ opportunity_value_snapshot : values + opportunity_record ||--o{ forecast_snapshot : forecasts + + commercial_account ||--o{ customer_outcome_record : seeks + commercial_account ||--o{ complaint_record : reports + commercial_account ||--o{ satisfaction_observation : measures + commercial_account ||--o{ relationship_assessment : assesses + + model_artifact ||--o{ forecast_snapshot : produces + model_artifact ||--o{ relationship_assessment : produces + source_receipt ||--o{ evidence_reference : anchors + audit_event ||--o{ outbox_event : accompanies +``` + +## 4. Identity and tenancy + +### `tenant_account` + +Represents the customer isolation boundary. It is not a billing account; billing is referenced from the Billing Control Plane. + +Required fields: + +```text +tenant_account_id +tenant_slug +lifecycle_status_code +default_locale_code +created_at +updated_at +``` + +### `workspace_record` + +A bounded operating space inside a tenant. A tenant may separate regions, business units, or sales processes without creating a separate security tenant. + +### `workspace_member` + +References a verified Keyverse subject. It may optionally reference an Orgmetra worker record, but ELUNVERA does not copy employment truth. + +## 5. Party model + +### `party_record` + +Canonical tenant-local identity for a person, organization, or group. + +```text +party_record_id +tenant_account_id +party_kind_code +canonical_display_name +lifecycle_status_code +created_at +updated_at +``` + +The `party_kind_code` is structural (`person`, `organization`, `group`), not a commercial role such as customer or partner. + +### Type extensions + +- `person_party` +- `organization_party` +- `group_party` + +Each extension uses the same `party_record_id` as primary and foreign key. + +### `party_name_record` + +Stores legal, preferred, localized, historical, and source-observed names with valid intervals and scripts/locales. + +### `contact_point_record` + +Stores email, phone, postal, URI, or other contact points with: + +- verification status; +- source; +- purpose compatibility; +- valid interval; +- confidentiality classification; +- preferred-use flag within a defined purpose. + +An email address is not a person identity. + +### `external_object_mapping` + +```text +external_object_mapping_id +tenant_account_id +source_authority_code +external_object_type_code +external_object_key +internal_object_type_code +internal_object_id +mapping_valid_time +mapping_status_code +source_receipt_id +``` + +A unique constraint on tenant, source authority, object type, and external key prevents duplicate ingestion. + +## 6. Commercial account model + +### `commercial_account` + +Represents a tenant’s managed commercial relationship centered on a party or defined group of parties. + +It is distinct from `organization_party`. One organization may have multiple commercial accounts by region, contract scope, business unit, or lifecycle, and one account may involve multiple organizations. + +### `account_party_binding` + +Links parties to a commercial account and records the binding role and valid interval. + +### `account_role_assignment` + +Stores time-valid roles such as prospect, active customer, former customer, implementation partner, reseller, strategic partner, or supplier. Role types are versioned tenant configuration, not hard-coded identity types. + +### `account_team_assignment` + +Links workspace members to an account with role, authority, valid interval, source, and optional Orgmetra assignment reference. + +## 7. Relationship model + +### `relationship_record` + +A relationship is a fact with its own identity. + +Required fields: + +```text +relationship_record_id +tenant_account_id +relationship_type_id +relationship_context_type_code +relationship_context_id +truth_status_code +relationship_valid_time +relationship_recorded_time +source_authority_code +confidence_value +confidence_method_code +disclosure_policy_id +created_by_actor_ref +``` + +Rules: + +- `confidence_value` is required for inferred facts and absent for authoritative facts unless an explicit measurement applies. +- Confidence is not permission to disclose. +- A relationship may have more than two participants. +- The same participants may have multiple relations in different contexts. +- A rejected proposal remains historically visible to authorized reviewers. + +### `relationship_participant` + +```text +relationship_participant_id +relationship_record_id +party_record_id +participant_role_code +participant_order +``` + +### `relationship_type_version` + +Versioned vocabulary including directionality, allowed participant roles, symmetry, transitivity, context types, and validation rules. + +A transitive type must not imply global authority across unrelated contexts. + +## 8. Evidence and source model + +### `source_receipt` + +Immutable receipt for a source object, import, connector observation, manual assertion, or model run. + +```text +source_receipt_id +tenant_account_id +source_authority_code +source_object_key +source_hash_sha256 +captured_at +knowledge_cutoff +collector_version +classification_code +raw_artifact_reference +``` + +### `evidence_reference` + +Connects a domain fact to a bounded source locator without copying all source content. + +```text +evidence_reference_id +source_receipt_id +subject_type_code +subject_id +source_locator +assertion_role_code +excerpt_hash_sha256 +review_status_code +``` + +## 9. Interaction and commitment model + +### `interaction_record` + +```text +interaction_record_id +tenant_account_id +commercial_account_id +interaction_type_code +occurred_time +recorded_at +source_authority_code +source_receipt_id +confidentiality_code +summary_status_code +``` + +Raw email or calendar bodies are not mandatory. Metadata and source references can create a useful timeline without copying content. + +### `interaction_participant` + +Links parties and workspace members to the interaction with role and attendance/status metadata. + +### `commitment_record` + +```text +commitment_record_id +tenant_account_id +commercial_account_id +commitment_subject +commitment_status_code +commitment_valid_time +due_time +owner_party_id +beneficiary_party_id +source_interaction_id +truth_status_code +``` + +### `commitment_transition` + +Append-only status transition with actor, business time, recorded time, reason, evidence, and external work reference. + +## 10. Opportunity model + +### `sales_process_version` + +An immutable released sales process. New definitions produce new versions. + +### `sales_stage_definition` + +Defines stage code, display order, entry/exit evidence policy, and allowed transitions. It does not define a default probability. + +### `opportunity_record` + +```text +opportunity_record_id +tenant_account_id +commercial_account_id +workspace_record_id +opportunity_title +opportunity_status_code +sales_process_version_id +opened_at +expected_decision_time +closed_at +current_version_number +``` + +### `opportunity_stage_transition` + +Append-only stage event with previous and new stage, business time, actor, evidence, reason, and process version. + +### `opportunity_party_role` + +Time-valid stakeholder or participating-organization role within the opportunity. Role vocabulary is configurable and does not impose a universal “buyer” object. + +### `opportunity_value_snapshot` + +```text +opportunity_value_snapshot_id +opportunity_record_id +value_type_code +quantity_value +unit_code +currency_code +amount_value +valid_at +recorded_at +source_authority_code +assumption_reference +``` + +### `forecast_snapshot` + +```text +forecast_snapshot_id +opportunity_record_id +forecast_source_code +forecast_category_code +probability_estimate +probability_lower_bound +probability_upper_bound +model_artifact_id +knowledge_cutoff +recorded_at +``` + +A model estimate requires bounds and a model artifact. A human category may exist without a numeric probability. + +## 11. Customer outcomes, complaints, and satisfaction + +### `customer_outcome_record` + +Defines an outcome in customer language, owner, observation period, measure references, status, and evidence. + +### `complaint_record` + +Stores complaint receipt and current projection. The complete history is in `complaint_transition` and related evidence. + +### `complaint_transition` + +States include received, acknowledged, triaged, investigating, response_proposed, responded, remedy_in_progress, verification_pending, closed, rejected, withdrawn, and reopened. Tenant profiles may refine these without removing audit meaning. + +### `satisfaction_observation` + +References a measurement procedure or instrument version, population, occasion, respondent role, score artifact, uncertainty, and source. + +### `relationship_assessment` + +A released assessment with model artifact, target population, time window, estimate, uncertainty, evidence, limitations, and abstention reason where no estimate is defensible. + +## 12. Model evidence + +### `model_artifact` + +```text +model_artifact_id +tenant_account_id +model_purpose_code +model_name +model_version +code_commit_sha +data_manifest_hash +feature_contract_hash +prompt_hash +provider_model_ref +population_scope_ref +validation_report_ref +approved_at +retired_at +``` + +### `model_claim` + +Stores each generated or calculated claim, evidence references, verification status, uncertainty, and disposition. + +## 13. Privacy and disclosure + +### `purpose_definition` + +Versioned purpose taxonomy and allowable field classes. + +### `communication_preference` + +Party, channel, purpose, status, effective interval, source, and proof. + +### `processing_basis_record` + +Stores a policy/legal reference and scope. The schema does not declare legal compliance by itself. + +### `disclosure_policy` + +Defines who may receive which field class, for what purpose, in which relationship context, and with what onward-disclosure restriction. + +### `data_rights_case` + +Tracks access, export, correction, restriction, objection, portability, deletion, and related workflow with identity-verification and response receipts. + +### `retention_policy_version`, `legal_hold_record`, `disposition_record` + +Retention and deletion are versioned decisions. Legal hold blocks disposition. Disposition records what was deleted, anonymized, retained, or excluded and why. + +## 14. Audit and messaging + +### `audit_event` + +Append-only actor, purpose, action, target, before/after hashes, result, business time, recorded time, and correlation fields. Sensitive field values are not copied into audit payloads. + +### `outbox_event` + +Stores canonical event payload hash, schema revision, aggregate reference, publish status, attempts, and next retry time. + +### `inbox_event` + +Stores consumer deduplication and processing result. + +### `projection_receipt` + +Records source event, target projection version, payload hash, and processing result. + +## 15. Temporal constraints + +Examples of facts that must not overlap within the same scoped key: + +- a source external object mapping to two active internal objects; +- a party’s preferred contact point for the same purpose and channel when policy requires one; +- one active primary account owner within a configured account-role scope; +- one current canonical sales-process version per workspace; +- one active communication preference statement from the same authority and purpose. + +The exact constraints belong in migrations and integration tests, not solely in application validation. + +## 16. Merge and split invariants + +Party/account merge must: + +1. create a reviewed merge plan; +2. enumerate conflicting identifiers, relationships, contact points, privacy policies, and external mappings; +3. preserve source records and redirection lineage; +4. be idempotent; +5. support reversal when downstream irreversible actions have not made reversal unsafe; +6. never merge across tenants; +7. not infer sameness solely from name or email similarity. + +## 17. Data export contract + +Every export contains: + +- manifest version; +- tenant, purpose, subject, and authorization references; +- object counts and schemas; +- knowledge cutoff; +- source and transformation receipts; +- included and excluded field classes; +- hashes; +- generated time and expiry; +- partial-failure or omission reasons. + +## 18. Data quality invariants + +- Every canonical party has one structural type. +- Every commercial account has at least one active party binding while active. +- Every opportunity stage transition references the sales-process version in effect. +- Every model-derived numeric estimate references an approved model artifact. +- Every inferred relationship has evidence and confidence method. +- Every external source object has a stable mapping or explicit unresolved state. +- Every mutation creates an audit event and operation receipt. +- Every tenant-owned reference is same-tenant or an opaque authorized external reference. diff --git a/docs/OPERABILITY.md b/docs/OPERABILITY.md new file mode 100644 index 0000000..60adb50 --- /dev/null +++ b/docs/OPERABILITY.md @@ -0,0 +1,151 @@ +# ELUNVERA Operability Baseline + +- **Document version:** 0.1 +- **Status:** Proposed operational baseline +- **Date:** 2026-08-27 + +## 1. Operating objective + +Operate ELUNVERA as a recoverable, observable, tenant-isolated customer system of record. Operational health means not only process liveness but the ability to authenticate, commit canonical writes, publish events, execute bounded jobs, protect data, and restore service. + +## 2. Runtime profiles + +### Development + +Compose-compatible local profile using Podman, Colima, or Docker; ephemeral synthetic data; no production credentials. + +### Single-customer isolated deployment + +Dedicated application, database, object storage, and Keyverse realm or tenant mapping. Suitable for regulated or data-sovereign customers. + +### Multi-tenant SaaS + +Shared control plane with database-enforced isolation, fair scheduling, tenant-aware capacity, and regional deployment policy. + +All profiles use the same contracts and migration history. + +## 3. Health endpoints + +| Endpoint | Meaning | Dependency checks | +|---|---|---| +| `/healthz` | process liveness | event loop and internal watchdog only | +| `/startupz` | startup completion | configuration, contract version, migrations | +| `/readyz` | safe to receive traffic | DB read/write path, key availability, queue admission, required policy | + +An optional provider outage does not fail core readiness unless the requested profile marks that provider as mandatory. Readiness output is bounded and exposes no secret or internal topology. + +## 4. Service-level objectives + +Initial GA targets: + +- authenticated core API availability: 99.9% monthly; +- accepted canonical writes durability: 99.999% excluding declared disaster scenarios; +- p95 core read latency: 500 ms for documented baseline workload; +- p95 core write latency: 750 ms; +- outbox publication lag: 99% under 60 seconds; +- customer-visible job start lag: 99% under 2 minutes under contracted capacity; +- restoration point objective: 15 minutes; +- restoration time objective: 4 hours for the initial profile. + +SLOs are measured over low-cardinality signals and accompanied by multi-window burn-rate alerts. + +## 5. Telemetry + +### Metrics + +- request count, latency, result class, and route template; +- authorization outcome by policy code, not personal identity; +- DB pool use, wait, transaction duration, lock wait, and rollback; +- outbox/inbox lag, retries, dead letters, and deduplication; +- job queue depth, age, execution, cancellation, and failure code; +- object-storage and export outcomes; +- connector latency, circuit state, and bounded error category; +- model job cost/usage references without prompt content; +- tenant resource quota and saturation using opaque tenant labels where permitted. + +### Traces + +Traces propagate correlation and causation IDs across domain, outbox, worker, and adapter boundaries. They exclude raw notes, messages, names, contact details, access tokens, and unrestricted tenant identifiers. + +### Logs + +Structured events use stable error codes. No stack trace is returned to a customer. Sensitive diagnostic logs require time-bound privileged access and retention. + +## 6. Capacity management + +Capacity models include tenant count, account count, relationship count, interaction volume, outbox volume, timeline query depth, export volume, job concurrency, and projection size. Autoscaling is not a substitute for bounded work. + +Connection pools and Rust worker pools are fixed from measured capacity. External libraries must not create uncontrolled nested pools or thread oversubscription. + +## 7. Backpressure + +- synchronous paths reject oversized or over-budget work before allocation; +- queues use bounded admission and tenant fairness; +- workers lease jobs with heartbeat and safe recovery; +- retries are bounded and preserve idempotency; +- optional model or provider work degrades to an explicit unavailable state; +- core account and opportunity writes do not depend on an LLM. + +## 8. Backup and restoration + +- encrypted base backup plus WAL or equivalent point-in-time recovery; +- object-storage versioning and retention policy; +- key and configuration backup with separate access controls; +- schema and release manifest stored with each backup series; +- scheduled restoration into an isolated environment; +- record-count, hash, temporal, RLS, outbox, object, and projection checks after restore; +- documented evidence and remediation for every rehearsal. + +A backup that has not been restored successfully is not accepted as recovery evidence. + +## 9. Migration operation + +Migrations use expand, backfill, verify, and contract phases. The runtime fails closed if schema is ahead or behind the supported compatibility window. Long backfills are resumable, tenant-bounded, observable, and do not hold unbounded locks. + +Migration rehearsals cover clean install and upgrade from the previous supported release. Rollback feasibility is declared per migration; irreversible migrations require restore or forward-fix procedures. + +## 10. Incident response + +Severity classification considers customer impact, confidentiality, integrity, availability, legal obligation, and commercial consequences. Runbooks cover: + +- authentication or tenant-isolation failure; +- data corruption or erroneous merge; +- connector duplication; +- key loss or rotation failure; +- model/provider data exposure; +- queue saturation; +- database failover and restore; +- supply-chain compromise; +- privacy request breach; +- export to an unauthorized recipient. + +Incident evidence may feed the GRC product but ELUNVERA remains the source for its operational audit facts. + +## 11. Administrative safety + +- no routine operation through direct database edits; +- all privileged commands have dry-run where feasible; +- bulk and destructive actions require receipts and approval; +- emergency access is time-limited, purpose-bound, and alerted; +- support impersonation is disabled or implemented as explicit delegated view with a persistent banner and audit record; +- maintenance mode distinguishes read-only from unavailable. + +## 12. Release and rollback + +A release includes signed OCI image, SBOM, provenance, migrations, contract compatibility report, test evidence, known limitations, rollback coordinates, and CHANGELOG. Promotion uses the same artifact digest across environments. + +Rollback never rewrites history. If the database has crossed an irreversible boundary, the release plan specifies forward fix or restore rather than claiming binary rollback. + +## 13. Operational readiness gate + +No production deployment until: + +- core SLO signals and paging are live; +- on-call ownership and escalation exist; +- clean install and upgrade rehearsal pass; +- backup and restoration evidence passes; +- tenant isolation and security checks pass; +- capacity baseline and limits are documented; +- incident and data-rights runbooks are reviewed; +- support can identify the current release and contract versions; +- known residual risks have owners and expiration dates. diff --git a/docs/PRD.md b/docs/PRD.md new file mode 100644 index 0000000..ca92434 --- /dev/null +++ b/docs/PRD.md @@ -0,0 +1,366 @@ +# ELUNVERA Product Requirements Document + +- **Document version:** 0.1 +- **Status:** Proposed product baseline +- **Date:** 2026-08-27 +- **Product:** ELUNVERA +- **Repository:** `ContextualWisdomLab/ELUNVERA` +- **Primary branch:** `develop` + +## 1. Executive summary + +ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence platform. It is designed for organizations whose customer context is fragmented across email, meetings, documents, account plans, opportunity records, support cases, customer feedback, and the memory of individual employees. + +The product converts that scattered context into a governed customer relationship record, a time-valid account and stakeholder model, and a prioritized queue of evidence-linked actions. Human judgment remains authoritative. ELUNVERA may propose interpretations, risks, and next actions, but it does not silently send messages, change opportunity stages, close cases, or disclose customer information. + +## 2. Product vision + +> Help every customer-facing team understand the relationship as it actually exists, see what changed, and take the next defensible action with evidence. + +ELUNVERA broadens CRM beyond a contact database or sales pipeline. Its five cross-functional product processes are: + +1. relationship and account strategy; +2. value and outcome definition; +3. multichannel interaction integration; +4. governed information and evidence management; +5. performance, satisfaction, and relationship assessment. + +These processes align with the strategic, cross-functional view of CRM described by Payne and Frow rather than treating CRM as a sales-force data-entry tool. + +## 3. Problem statement + +Customer-facing teams currently experience the following failures: + +- account and stakeholder truth is duplicated across spreadsheets, inboxes, chat, and individual notes; +- organizational and interpersonal roles change over time but records are overwritten; +- a meeting, email thread, complaint, contract discussion, and delivery issue are not connected into one decision context; +- opportunity stages and probabilities are often based on local convention rather than calibrated evidence; +- a new account owner cannot reconstruct commitments and stakeholder history; +- important customer facts are exposed too broadly or hidden by destructive masking; +- generic AI summaries omit provenance, uncertainty, and the next action; +- customer satisfaction and relationship “health” are reduced to opaque weighted scores; +- integrations copy source data without a stable authority, idempotency, or deletion contract. + +## 4. Product principles + +### P-01 Relationship truth is temporal + +Roles, affiliations, account status, stakeholder participation, ownership, and disclosure policy change over time. ELUNVERA preserves historical truth instead of overwriting it. + +### P-02 Evidence precedes inference + +A relationship, commitment, risk, or recommendation must link to source evidence or explicitly declare that it is manually asserted. Inferred claims never become authoritative facts automatically. + +### P-03 Human judgment remains authoritative + +The product reduces cognitive load and proposes a defensible next action. It does not replace customer-facing judgment or authority. + +### P-04 Context is purpose-bound + +Authorized operational users may need unmasked customer information. ELUNVERA protects that information through purpose limitation, field selection, least privilege, disclosure policy, encryption, and audit rather than making the system unusable through universal masking. + +### P-05 No arbitrary commercial scoring + +Forecast probability, relationship health, stakeholder influence, lead score, and churn risk may not be computed from undocumented weights or stage defaults. A score requires a versioned model, defined outcome, calibration evidence, uncertainty, and monitoring. + +### P-06 Federated products retain their own truth + +ELUNVERA integrates with other CWL products without copying their authority or implementation. + +### P-07 Customer copy supports the next action + +Every alert, empty state, error, and AI response explains what happened, why it matters, and the available next action without exposing internal service names. + +## 5. Target customers + +### Primary segments + +- B2B organizations with complex, multi-person accounts; +- enterprise sales and account-management teams; +- customer-success and renewal teams; +- professional-services and solution-delivery organizations; +- regulated organizations that require data lineage, auditability, and purpose-aware access. + +### Initial deployment profile + +The first commercial profile is a multi-tenant or customer-isolated enterprise SaaS deployment for Korean and international B2B account teams, with Korean and English user experiences and optional customer-controlled connectors. + +## 6. Personas + +| Persona | Primary job | Critical concern | +|---|---|---| +| Account executive | Progress an opportunity with accurate stakeholder and commitment context | Avoid stale or invented deal confidence | +| Account manager | Preserve and grow a long-term commercial relationship | Understand role changes and customer outcomes | +| Customer success manager | Coordinate adoption, risk, complaint, and renewal activity | Separate observed signals from inferred risk | +| Sales manager | Review pipeline and coach account teams | See evidence and forecast uncertainty, not only totals | +| Revenue operations analyst | Govern stages, taxonomies, data quality, and forecast processes | Versioned processes and reproducible metrics | +| Customer-service lead | Handle complaints and service recovery | ISO-aligned complaint history and closure evidence | +| Privacy or security officer | Control customer-data use and disclosure | Purpose, retention, access, export, and incident evidence | +| Executive | Understand material relationship changes and commercial exposure | Concise, exact, drillable information | +| Platform administrator | Configure tenants, roles, integrations, and policies | Fail-closed isolation and operability | + +## 7. Core jobs to be done + +### JTBD-01 Prepare for a customer interaction + +When a customer meeting is approaching, assemble the current account context, recent changes, open commitments, stakeholder roles, prior decisions, and unresolved risks with evidence so the user can prepare without searching multiple systems. + +### JTBD-02 Understand an account + +When ownership changes or an issue arises, show the organization hierarchy, account roles, people, relationship history, products or services in context, and current outcomes without flattening them into one score. + +### JTBD-03 Progress a commercial opportunity + +When a team updates an opportunity, preserve the stage transition, evidence, stakeholders, criteria, values, assumptions, and forecast snapshot so later reviews can reproduce why the change occurred. + +### JTBD-04 Protect commitments + +When a customer or team member makes a commitment, track the authoritative status, owner, due interval, evidence, and downstream action without converting email content into an unreviewed task automatically. + +### JTBD-05 Recover service and complaints + +When a customer reports a complaint, preserve receipt, classification, ownership, communication, remedy, response, verification, and closure evidence. + +### JTBD-06 Measure outcomes responsibly + +When leaders need a customer or relationship assessment, use versioned instruments and calibrated models, report uncertainty and population limits, and retain evidence from observation through decision. + +### JTBD-07 Exercise data rights + +When a person requests access, export, correction, restriction, or deletion, identify all relevant authoritative and projected data, execute a policy-controlled workflow, and preserve a receipt without deleting protected audit or legal-hold facts. + +## 8. Product scope + +### 8.1 P0 — Foundation + +- tenant and workspace configuration; +- Keyverse identity integration and role mapping; +- commercial account registry; +- party registry for people, organizations, and groups; +- time-valid account and party roles; +- first-class relationship facts with evidence and disclosure policy; +- account-team assignments; +- contact points and purpose-specific communication preferences; +- manual interactions, notes, evidence references, and commitments; +- opportunity registry, configurable stage definitions, stage history, stakeholders, values, products or offerings by reference, and forecast snapshots; +- immutable audit and transactional outbox; +- deterministic CSV/JSON import and export; +- account search and duplicate-candidate workflow; +- Korean and English interface baseline; +- account overview, relationship map, timeline, opportunity workspace, and action queue. + +### 8.2 P1 — Integrated context + +- naruon interaction metadata and source references; +- ThreadWeave thread references; +- LineageWeave inferred-lineage proposals; +- ScopeWeave work-item references; +- Semantic Data Portal ontology links; +- RankWeave retrieval fusion; +- evidence-grounded account and meeting briefs through contextual-orchestrator; +- customer complaint workflow aligned to ISO 10002; +- satisfaction observation and monitoring workflow aligned to ISO 10004; +- customer outcome and renewal context; +- controlled data-rights workflow; +- administrative data-quality console. + +### 8.3 P2 — Calibrated relationship intelligence + +- TEPP temporal event and relationship analysis; +- fast-mlsirm calibration for LLM-as-a-judge or rater-like assessments; +- model registry, population scope, true-parameter recovery evidence, drift monitoring, and uncertainty; +- account health and opportunity risk as evidence-based model artifacts; +- forecast calibration and outcome analysis; +- explainable intervention recommendations; +- opt-in Figma-validated advanced graph and temporal visual analytics. + +## 9. Explicit non-goals + +ELUNVERA will not initially: + +- host mailboxes, SMTP, IMAP, CalDAV, or WebDAV; +- provide full marketing automation, ad targeting, or campaign execution; +- replace ERP, CPQ, contract lifecycle, order management, accounting, or billing systems; +- replace ScopeWeave for project, WBS, ITSM, or generalized work management; +- replace Orgmetra for employee and employment truth; +- replace the Semantic Data Portal as an enterprise ontology and catalog; +- copy raw external-system data without source authority and retention contracts; +- derive high-stakes customer or employee decisions from a single LLM response; +- claim compliance certification merely because controls are documented. + +## 10. Functional requirements + +### Account and party management + +- **FR-001:** The system shall create and version tenant-scoped commercial accounts. +- **FR-002:** The system shall represent people, organizations, and groups as separate party types under a canonical party identity. +- **FR-003:** The system shall preserve organization hierarchy and merger, subsidiary, partner, customer, prospect, and former-customer roles as time-valid relations rather than immutable entity types. +- **FR-004:** The system shall support duplicate candidates, review, merge, split, and merge reversal with provenance. +- **FR-005:** The system shall never use an email address as the permanent identity of a person or account. + +### Relationships and stakeholders + +- **FR-010:** A relationship shall include participants, type, context, valid interval, truth status, evidence, confidence when inferred, source authority, and disclosure policy. +- **FR-011:** The same parties may have multiple simultaneous relationships in different contexts. +- **FR-012:** Opportunity and account stakeholder roles shall be versioned and organization-configurable. +- **FR-013:** The system shall distinguish manually asserted, observed, inferred, proposed, rejected, and superseded relationship facts. + +### Interactions and commitments + +- **FR-020:** The system shall record interactions without requiring raw message bodies. +- **FR-021:** External interaction references shall identify source system, immutable source key, captured time, and source hash or receipt when available. +- **FR-022:** A commitment shall include status, owner, beneficiary, valid/due interval, evidence, and completion or supersession history. +- **FR-023:** Imported interaction and commitment items shall be idempotent at item level. +- **FR-024:** AI-extracted commitments shall remain proposed until accepted by an authorized user or an approved deterministic rule. + +### Opportunities and forecasts + +- **FR-030:** Sales processes and stage definitions shall be versioned by tenant or workspace. +- **FR-031:** Stage transitions shall be append-only and include actor, reason, evidence, business time, and recorded time. +- **FR-032:** Monetary values shall use exact decimal quantities and explicit ISO 4217 currency codes. +- **FR-033:** Forecast snapshots shall be immutable and distinguish user category, manager adjustment, and model estimate. +- **FR-034:** Model estimates shall include model version, training/evaluation population, estimate interval, calibration evidence, and knowledge cutoff. +- **FR-035:** The system shall not infer forecast probability from stage alone. + +### Customer outcome and complaint management + +- **FR-040:** The system shall record desired customer outcomes, observation periods, measures, and evidence. +- **FR-041:** Complaint handling shall preserve receipt, acknowledgement, classification, owner, investigation, response, remedy, verification, escalation, and closure. +- **FR-042:** Satisfaction observations shall reference an instrument or defined measurement procedure and population. +- **FR-043:** Customer health assessments shall expose contributing evidence and uncertainty and may abstain. + +### Search and intelligence + +- **FR-050:** Search results shall preserve channel contribution, source, and access decision. +- **FR-051:** AI briefs shall cite ELUNVERA evidence references and distinguish facts, inferences, unknowns, and recommended actions. +- **FR-052:** The assistant shall not disclose data outside the user’s purpose, tenant, role, field, and relationship-disclosure policy. +- **FR-053:** Irreversible or external actions shall require an explicit human approval or a separately approved automation policy. + +### Privacy, security, and data rights + +- **FR-060:** Every request shall carry verified tenant, actor, role, purpose, and correlation context. +- **FR-061:** Contact and relationship fields shall support purpose-specific access and export rules. +- **FR-062:** The system shall support access, export, correction, restriction, retention, legal hold, and deletion workflows with receipts. +- **FR-063:** Audit, legal-hold, transaction, and historical relationship facts shall not be silently deleted. +- **FR-064:** Event payloads shall use opaque references and exclude secrets and unnecessary raw PII. + +### Administration and integration + +- **FR-070:** Administrators shall configure role taxonomies, sales processes, field policies, retention profiles, integration capabilities, and model permissions through versioned configuration. +- **FR-071:** External systems shall connect through capability-specific adapters, not one lowest-common-denominator integration interface. +- **FR-072:** Every provider command and webhook shall be idempotent, signed or authenticated, replay-protected, and recorded. +- **FR-073:** The system shall retain a provider-object mapping rather than adding provider-specific IDs to core domain tables. + +## 11. Non-functional requirements + +### Availability and reliability + +- **NFR-001:** Initial GA target is 99.9% monthly availability for authenticated API and web workflows, excluding announced maintenance. +- **NFR-002:** Accepted writes shall be durable before success is returned. +- **NFR-003:** Outbox publication shall be retryable and at-least-once; consumers shall be idempotent. +- **NFR-004:** Backup and point-in-time restoration shall be rehearsed before release. + +### Performance + +- **NFR-010:** Core account overview p95 server response time shall be under 500 ms for the release benchmark profile, excluding downstream AI calls. +- **NFR-011:** Search p95 shall be under 1.5 seconds for the release benchmark profile. +- **NFR-012:** Long-running exports, imports, model runs, and connector synchronizations shall use durable asynchronous jobs with status and cancellation. +- **NFR-013:** Product UI shall never wait synchronously for an LLM workflow to complete. + +### Scale baseline + +The first release benchmark shall cover: + +- 1,000 tenants; +- 1,000,000 commercial accounts; +- 20,000,000 parties; +- 100,000,000 interactions; +- 10,000,000 relationships; +- 5,000,000 opportunities; +- concurrent ingestion and read traffic with noisy-tenant controls. + +These are acceptance targets, not current performance claims. + +### Security and privacy + +- **NFR-020:** Cross-tenant access acceptance target is zero successful accesses across API, database, cache, search, export, and background jobs. +- **NFR-021:** All external data and model output shall be treated as untrusted input. +- **NFR-022:** Encryption in transit and at rest shall be mandatory for production. +- **NFR-023:** Customer-content logging shall be disabled by default. +- **NFR-024:** Security and privacy controls shall support ISO/IEC 27001:2022, ISO/IEC 27701:2025, SOC 2, CSAP, Korean PIPA, and GDPR deployment evidence without claiming certification. + +### Accessibility and internationalization + +- **NFR-030:** Web experiences shall conform to WCAG 2.2 AA. +- **NFR-031:** Every graph, chart, and timeline shall have an exact-value table and export representation. +- **NFR-032:** Korean and English shall ship together, with locale-safe dates, names, addresses, number formats, and sorting. +- **NFR-033:** Customer-facing copy shall describe the user’s next action rather than internal implementation boundaries. + +### Quality + +- **NFR-040:** ELUNVERA-owned shipped code shall have 100% production statement coverage, 100% production branch coverage, and 100% public API documentation coverage. +- **NFR-041:** Required GPU tests may not pass by being skipped. +- **NFR-042:** Deprecation warnings shall be corrected, not suppressed. +- **NFR-043:** Release artifacts shall include SBOM, provenance, signatures, compatibility metadata, and reproducible-build evidence. + +## 12. Primary user journeys + +### Journey A — Account preparation + +1. User opens the account judgment queue. +2. ELUNVERA shows changes since the user’s last verified view. +3. User opens an account overview with three bands: context, relationships, and action. +4. Recent interactions, open commitments, stage changes, customer outcomes, and unresolved evidence conflicts are visible. +5. The evidence-grounded assistant proposes a meeting brief and next actions. +6. User accepts, edits, or rejects each proposed action independently. + +### Journey B — Opportunity review + +1. Manager opens the opportunity workspace. +2. Current stage, complete stage history, stakeholder evidence, value snapshots, assumptions, and forecast sources are visible. +3. A model estimate is shown only when model release criteria are satisfied; otherwise the system abstains. +4. Manager records a review decision and reason without overwriting the prior forecast. + +### Journey C — Complaint recovery + +1. A complaint arrives through manual entry or a controlled connector. +2. ELUNVERA acknowledges receipt and records the source. +3. An owner investigates and links evidence, affected products, interactions, and commitments. +4. Response and remedy are approved and communicated through the source system. +5. Verification and closure are recorded; satisfaction follow-up is scheduled if permitted. + +## 13. Product success measures + +Success measures shall be segmented by tenant, account complexity, role, and adoption cohort. A metric is not a product goal merely because it is easy to count. + +| Dimension | Measure | +|---|---| +| Context efficiency | Median time from account open to evidence-backed action decision | +| Continuity | Proportion of active accounts with current ownership, stakeholder, and commitment context | +| Data quality | Duplicate rate, stale-role rate, unresolved identity rate, source-receipt completeness | +| Action reliability | Accepted commitments completed on time; proposed actions accepted, edited, or rejected | +| Forecast quality | Calibration error, interval coverage, bias, and drift by segment | +| Relationship measurement | Reliability, validity, invariance, and uncertainty of released instruments/models | +| Customer outcome | Complaint cycle time, verified closure, recurrence, and satisfaction follow-up | +| Trust | Unauthorized access attempts blocked, data-rights completion, export provenance completeness | +| Operability | Availability, latency, job recovery, restore success, and incident recurrence | +| Accessibility | Automated and manual WCAG conformance and assistive-technology journey success | + +## 14. Release acceptance + +A first production release may be proposed only when: + +- the P0 vertical operates end to end on a clean deployment; +- current-head tests and security checks pass; +- tenant isolation is proven at API and database layers; +- migrations, rollback, backup, and restore are rehearsed; +- exact user journeys pass in Korean and English; +- accessibility journeys pass with keyboard and screen-reader evidence; +- no critical or high unaccepted security finding remains; +- every numerical model in the release has documented validation and uncertainty; +- documentation and observed implementation state are consistent; +- signed artifacts, SBOM, provenance, runbooks, and changelog are complete. + +## 15. Assumptions and open implementation decisions + +This baseline intentionally decides the product boundary and quality contract but does not claim that a runtime exists. Implementation details such as exact web framework versions, message transport, object-storage provider, deployment platform, and first customer-specific connectors must be selected through reviewed ADRs when executable work begins. diff --git a/docs/PRIVACY.md b/docs/PRIVACY.md new file mode 100644 index 0000000..4a372eb --- /dev/null +++ b/docs/PRIVACY.md @@ -0,0 +1,141 @@ +# ELUNVERA Privacy and Data-Governance Baseline + +- **Document version:** 0.1 +- **Status:** Proposed privacy baseline +- **Date:** 2026-08-27 + +## 1. Objective + +ELUNVERA processes business contact, relationship, communication, complaint, commercial, and potentially sensitive contextual data. Privacy controls must allow authorized customer work while preventing reuse, overexposure, indefinite retention, hidden profiling, and unreviewed automated decisions. + +## 2. Core principles + +1. **Purpose limitation:** each read, export, model job, and disclosure carries an approved `purpose_code`. +2. **Data minimization:** collect and expose only fields required by that purpose. +3. **Temporal accuracy:** preserve historical facts while clearly distinguishing current status. +4. **Source transparency:** retain source authority, evidence reference, and whether a fact is asserted, observed, or inferred. +5. **Human review:** inferred relationship or commercial claims are reviewable and correctable. +6. **Retention by category:** no universal indefinite CRM retention. +7. **Operational usability:** authorized users receive the exact business fields they need; protection is not implemented as indiscriminate masking. +8. **Tenant and context separation:** overlapping relationships do not permit disclosure across unrelated customer or organizational contexts. + +## 3. Data categories + +| Classification | Examples | Default treatment | +|---|---|---| +| Public | published organization address, public role | normal access within tenant policy | +| Internal | account segmentation, general notes | authenticated tenant access | +| Confidential commercial | opportunity value, strategy, forecast | limited roles and purpose | +| Restricted personal | personal contact data, communication preferences | purpose-aware field selection | +| Restricted complaint | complaint narrative, remedy, adverse experience | case team and oversight roles | +| Highly restricted | legal hold material, protected characteristic, sensitive disclosure | explicit policy and audit approval | + +A field may have a stricter contextual classification than its base schema indicates. + +## 4. Purpose registry + +`purpose_definition` is versioned and records: + +```text +purpose_code +purpose_title +allowed_actor_roles +allowed_data_categories +allowed_operations +retention_effect +model_processing_allowed +external_disclosure_allowed +legal_basis_profile +valid_time +``` + +Examples include `account_management`, `opportunity_execution`, `complaint_resolution`, `customer_support`, `data_rights_fulfillment`, `security_investigation`, and `model_validation`. Free-form purpose text does not grant access. + +## 5. Processing basis and preference + +ELUNVERA records a reference to the applicable processing basis and its scope; it does not assume that consent is the only lawful basis. Communication preferences are channel-, purpose-, identity-, and time-specific. A global opt-out cannot be overwritten by a local campaign import. + +Preference evaluation returns a decision receipt with the effective rule and source. Marketing permissions are separated from operational service communications. + +## 6. Disclosure policy + +A relationship may carry a disclosure policy because the same person can participate in multiple commercial, employer, partner, and personal contexts. Disclosure is evaluated against: + +```text +tenant +workspace +requesting actor +purpose +relationship context +data category +recipient context +valid time +policy version +``` + +Information learned in one context is not silently propagated to another because a person or organization appears in both. + +## 7. Data-subject rights + +`data_rights_case` supports access, correction, deletion, restriction, objection, portability, and consent or preference withdrawal where applicable. The workflow includes: + +```text +received → identity_verification → scoped → collecting → reviewed + → fulfilled | partially_fulfilled | rejected_with_basis +``` + +Every outcome includes included data, exclusions and legal basis, source systems, unresolved mappings, export hash, approver, and fulfillment time. Legal hold and authoritative transaction-history constraints are visible, not silently ignored. + +## 8. Retention and disposition + +Retention policies are versioned by record class, purpose, jurisdiction profile, contract, and tenant. Disposition is a job with dry-run preview, item-level decisions, legal-hold checks, immutable receipt, and post-action verification. + +Deletion does not mean erasing evidence required to prove that a lawful deletion occurred. Minimal tombstones may preserve opaque identity, policy version, operation receipt, and cryptographic digest without retaining the deleted content. + +## 9. Data export and portability + +Exports are purpose-specific and reproducible. An export manifest contains: + +- requester and approval; +- tenant and subject scope; +- temporal lens and knowledge cutoff; +- included record classes and fields; +- excluded fields with policy reasons; +- source authority and provenance; +- schema and software versions; +- artifact hash and encryption information; +- expiration and download receipt. + +Bulk export is asynchronous, encrypted, rate-limited, and maker-checker controlled. + +## 10. Model processing and profiling + +A model job must declare: + +```text +outcome_definition +input_data_classes +training_or_inference_purpose +model_artifact_reference +provider_and_region +retention_behavior +human_review_role +appeal_or_correction_path +``` + +No hidden “relationship health,” “influence,” “lead quality,” or “churn” score is released without validity, fairness, calibration, uncertainty, and consequence review. A user can inspect the evidence and model status behind a claim. + +## 11. International and regional deployment + +The platform supports tenant-configurable residency, provider allowlists, and cross-border transfer controls. Data-processing agreements, subprocessor records, transfer mechanisms, and region-specific statutory interpretation are organizational responsibilities supported by records and policy, not automatically guaranteed by the software. + +## 12. Development and testing data + +- Production personal data is not copied into public repositories or ordinary developer fixtures. +- Real-person and real-organization names are anonymized in tests and documentation unless they are public standards bodies or product identities. +- Synthetic data is permitted for unit and simulation tests but is never presented as production evidence. +- Authorized production debugging uses audited, time-bounded, purpose-specific access and field minimization. + +## 13. Privacy evidence + +Release evidence includes data-flow inventory, field classification coverage, purpose tests, rights-workflow tests, retention simulation, legal-hold tests, export inspection, telemetry scan, model-input inspection, and cross-tenant disclosure tests. diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md new file mode 100644 index 0000000..ee42b6b --- /dev/null +++ b/docs/ROADMAP.md @@ -0,0 +1,84 @@ +# ELUNVERA Delivery Roadmap + +## M0 — Documentation and contract baseline + +**Exit criteria** + +- PRD, TRD, architecture, data model, security, privacy, threat model, UX, test, operability, ADR, OpenAPI, AsyncAPI, and schemas reviewed; +- product boundary accepted; +- no implementation or readiness claim mixed into documentation; +- `develop` integration branch and protected review policy established. + +## M1 — Identity, tenancy, and canonical CRM kernel + +- Rust workspace and repository quality gates; +- Keyverse OIDC context; +- tenant, workspace, member, party, account, and first-class relationship model; +- PostgreSQL 18.6 migration and RLS; +- audit, idempotency, ETag, outbox, and operation receipt; +- account overview read model without LLM dependency. + +**Buyer outcome:** governed account and stakeholder history. + +## M2 — Interaction, commitment, and opportunity vertical + +- manual and normalized interaction metadata; +- commitment lifecycle; +- versioned sales process and opportunity history; +- exact money and forecast snapshots; +- timeline and account three-band UI; +- import dry-run and provider mapping. + +**Buyer outcome:** auditable opportunity progression and protected promises. + +## M3 — Complaints, outcomes, and privacy operations + +- complaint and remedy workflow; +- desired and observed customer outcomes; +- satisfaction observation registry; +- communication preference and processing-basis references; +- rights cases, export manifests, retention, hold, and disposition. + +**Buyer outcome:** closed-loop service recovery and governed customer data. + +## M4 — CWL context integrations + +- naruon observation and action-reference adapter; +- ThreadWeave and LineageWeave evidence projection; +- RankWeave search fusion; +- Semantic Data Portal ontology references; +- ScopeWeave work-execution reference; +- Billing Control Plane entitlement reference; +- reconciliation and connector operability. + +**Buyer outcome:** scattered context connected without duplicating source authorities. + +## M5 — Calibrated relationship intelligence + +- contextual-orchestrator model jobs; +- evidence-grounded meeting briefs and proposed claims; +- model registry, claim review, and provider/prompt trace; +- TEPP and fast-mlsirm integration for validated temporal or measurement use cases; +- true-parameter, calibration, fairness, and uncertainty evidence; +- no heuristic score fallback. + +**Buyer outcome:** explainable assistance rather than opaque CRM scoring. + +## M6 — Enterprise scale and GA + +- multi-region or customer-isolated deployment profiles; +- 100,000 accounts and 10,000,000 relationship/interaction facts benchmark profile; +- k6 load and hot-partition remediation; +- external security review and penetration test; +- backup/restore, key rotation, incident, upgrade, and rollback evidence; +- WCAG 2.2 AA audit; +- signed OCI artifacts, SPDX SBOM, provenance, release notes, and support policy; +- commercial packaging and billing integration. + +## Sequencing rules + +- Do not implement intelligence before canonical account, relationship, temporal, and evidence contracts. +- Do not implement a graph as the source of truth. +- Do not expose production PII before identity, tenant, purpose, audit, retention, and restore gates. +- Do not call a feature GA because a document or demo exists. +- Each milestone is split into independently reviewable vertical PRs and keeps the product usable at the end of the slice. diff --git a/docs/SECURITY.md b/docs/SECURITY.md new file mode 100644 index 0000000..bcec9e4 --- /dev/null +++ b/docs/SECURITY.md @@ -0,0 +1,174 @@ +# ELUNVERA Security Architecture + +- **Document version:** 0.1 +- **Status:** Proposed security baseline +- **Date:** 2026-08-27 + +## 1. Security objective + +Protect customer relationship data, commercial strategy, communications metadata, opportunity value, complaints, identity links, and model evidence while preserving authorized operational use. ELUNVERA uses strong identity, tenant isolation, purpose-aware authorization, field selection, encryption, immutable audit, and bounded integration rather than universal destructive masking. + +## 2. Control framework baseline + +The product design is aligned to, but does not claim certification against: + +- ISO/IEC 27001:2022 and Amendment 1:2024; +- ISO/IEC 27701:2025; +- NIST Cybersecurity Framework 2.0; +- NIST Privacy Framework 1.0, while tracking the draft 1.1 revision; +- OWASP ASVS and OWASP API Security Top 10; +- SOC 2 trust-services concerns for security, availability, confidentiality, processing integrity, and privacy; +- Korean Personal Information Protection Act and its current Enforcement Decree; +- GDPR where territorial scope applies. + +Certification, legal compliance, or audit readiness requires implementation and independent evidence beyond these documents. + +## 3. Security boundaries + +### Trusted control plane + +- verified Keyverse identity context; +- authorization policy and purpose registry; +- canonical PostgreSQL system of record; +- cryptographic key-management interface; +- append-only audit and operation receipts. + +### Untrusted inputs + +- connector payloads; +- email and calendar observations; +- uploaded files and note content; +- webhooks; +- LLM output; +- imported CRM data; +- user-entered rich text; +- cross-tenant identifiers supplied by callers. + +Untrusted content remains data. It cannot alter authorization, tool permissions, model instructions, retention policy, or tenant scope. + +## 4. Identity and access control + +- Keyverse is the identity authority; ELUNVERA stores subject mappings, not passwords. +- OIDC validation checks exact issuer, audience, signature, token type, nonce where applicable, `nbf`, `iat`, and `exp`. +- Human, service, workflow, and delegated-agent principals are distinct. +- SCIM drives joiner, mover, and leaver lifecycle where configured. +- Role-based access is necessary but insufficient; every sensitive operation also evaluates tenant, workspace, relationship context, purpose, data classification, disclosure policy, and legal hold. +- Privileged changes such as bulk export, account merge, high-volume deletion, model release, and policy override require maker-checker approval. +- Guessed cross-tenant identifiers return a non-disclosing `404`. + +## 5. Tenant isolation + +Defense in depth includes: + +1. verified tenant context at ingress; +2. domain repository methods requiring that context; +3. PostgreSQL row-level security or an equivalent database-enforced boundary; +4. tenant-bound object-storage prefixes and encryption context; +5. tenant-bound search and graph projection namespaces; +6. contract tests proving cross-tenant access returns no data; +7. telemetry that omits raw tenant PII. + +A background worker may not bypass tenant enforcement merely because it is internal. It uses a scoped service principal and explicit job tenant. + +## 6. Data protection + +### In transit + +- TLS 1.3 preferred; TLS 1.2 permitted only where a reviewed compatibility profile requires it. +- Remote PostgreSQL connections use certificate verification. +- Service identities use short-lived credentials. + +### At rest + +- Storage encryption uses customer- or environment-scoped keys. +- Highly restricted fields may use application-level envelope encryption with versioned key references. +- Key rotation supports active and predecessor keys, bounded re-encryption jobs, receipts, and rollback. +- Backups are encrypted and restoration verifies key availability. + +### Field exposure + +API schemas define field classifications and purpose-specific views. The server excludes fields not needed for the approved purpose. Logging and analytics do not receive full record objects. + +## 7. Secrets + +- Secrets reside in a managed secret store or KMS-integrated vault. +- Source code, CI logs, events, traces, screenshots, fixtures, and support bundles contain no live secrets. +- Provider credentials are not distributed to every domain service; capability adapters receive only the credential they require. +- Secret rotation is tested without service redeployment where the provider permits it. + +## 8. Integration security + +Every adapter enforces: + +- exact destination host and port policy; +- allowed methods and content types; +- DNS-rebinding resistance; +- connection, request, and response timeouts; +- request and response size limits; +- redirect policy; +- signature or mutual-authentication verification; +- idempotency and replay defense; +- bounded retry with jitter; +- circuit breaking without data loss; +- source receipt and payload hash. + +A webhook is an external assertion. Signature verification, replay checks, and state-transition validation precede any canonical mutation. + +## 9. Content security + +- Rich text is stored in a safe structured representation and rendered through an allowlist sanitizer. +- JavaScript, macros, executable attachments, and external resource fetching are disabled in parsing workflows. +- File type is established from signatures and bounded parsing, not filename extension or caller `Content-Type` alone. +- Malware scanning and quarantine precede attachment availability. +- Spreadsheet exports neutralize formula injection. +- CSV, JSON, PDF, and Office exports preserve classification and access receipts. + +## 10. AI security + +- LLM calls go through contextual-orchestrator. +- Customer text is untrusted observation, never system instruction. +- Prompt templates, tool capability lists, model identity, provider, reasoning level, and evidence set are versioned. +- Models never receive credentials or unrestricted cross-tenant context. +- Tools are typed, bounded, and purpose-scoped. +- High-impact mutations terminate at human approval. +- Model claims are stored separately from authoritative facts. +- Indirect prompt-injection, data exfiltration, unsupported claim, and tool-escalation tests are release gates. + +## 11. Audit integrity + +Audit events include actor, tenant, purpose, command, target reference, prior and resulting versions, recorded time, correlation, decision reference, and policy outcome. High-volume raw content is referenced by digest rather than copied into the audit log. + +Audit rows are append-only. Corrections append compensating records. Retention and legal-hold policy governs deletion; administrators cannot silently erase privileged actions. + +## 12. Availability and abuse resistance + +- Per-principal and per-tenant rate and concurrency limits. +- Bounded page size, query depth, export size, graph traversal, and batch item count. +- Queue admission control and backpressure. +- Memory, CPU, database connection, and external-call budgets. +- Async jobs for expensive work. +- Tenant isolation of noisy workloads. +- Administrative emergency read-only mode. + +## 13. Supply chain + +- Dependencies and actions pinned by digest or full commit SHA. +- Rust lockfile and frontend lockfile are reviewed and immutable in release builds. +- SBOM uses SPDX. +- Builds generate provenance and signed artifacts. +- License, vulnerability, secret, SAST, dependency-review, and artifact-integrity checks are required. +- Release jobs use short-lived identity rather than long-lived publishing keys where supported. + +## 14. Security acceptance criteria + +A GA candidate must demonstrate: + +- zero unauthorized cross-tenant reads or writes in the adversarial suite; +- zero unauthenticated remote business endpoints; +- successful key rotation and restore rehearsals; +- duplicate and reordered webhook safety; +- bounded hostile payload handling; +- prompt-injection action-escalation rate of zero in the release corpus; +- no raw secrets or restricted PII in telemetry and build artifacts; +- independent security review of current-head code; +- documented residual risks and approved owners. diff --git a/docs/STORYBOARD.md b/docs/STORYBOARD.md new file mode 100644 index 0000000..b5db285 --- /dev/null +++ b/docs/STORYBOARD.md @@ -0,0 +1,41 @@ +# ELUNVERA Product Storyboard + +## Scene 1 — A changed relationship + +An account owner opens Home and sees: “The customer’s procurement lead changed yesterday. Two opportunity assumptions still reference the former lead.” The card states why it matters and offers **Review account**. + +## Scene 2 — Three-band account view + +The account page opens with account context, relationship structure, and action/risk arranged in three horizontal bands. The user does not see separate integration dashboards or an unexplained knowledge graph. + +## Scene 3 — Evidence inspection + +The user selects the new procurement role. An evidence drawer shows a public announcement, a verified meeting record, valid time, recorded time, and truth status. A conflicting email signature is shown as older evidence rather than overwritten. + +## Scene 4 — Opportunity decision + +The current opportunity stage lists assumptions and the affected stakeholder. The user changes the stage only after reviewing the process definition, evidence, effective date, and forecast consequence. A receipt confirms the immutable transition. + +## Scene 5 — Commitment protection + +A follow-up promised in a meeting is due soon. The system shows the commitment as confirmed and links the meeting evidence. A calendar connector is unavailable, but the message says: “Calendar updates are temporarily unavailable. Review this commitment manually or reconnect the source.” + +## Scene 6 — Complaint recovery + +A complaint appears in the action band because the remedy deadline approaches. The complaint workspace links the original issue, affected outcome, investigation, proposed remedy, and customer response. The next action is clear without a generic severity score. + +## Scene 7 — Responsible intelligence + +The system proposes that a stakeholder may have become a decision influencer. The card is labeled **Proposed interpretation**, shows evidence and uncertainty, and requires a reviewer. It never changes the stakeholder’s authoritative role silently. + +## Scene 8 — Handover + +When account ownership changes, the new owner sees the same history, former relationships, open commitments, and decision receipts. No employee’s private spreadsheet is required to understand the account. + +## Scene 9 — Data rights + +A privacy operator fulfills a request through a scoped case. The export preview explains which fields are included, what is excluded under legal hold or another basis, and where each record originated. + +## Scene 10 — Operational confidence + +After a recovery rehearsal, the operations dashboard confirms database restore, key availability, outbox consistency, projection rebuild, and tenant isolation. Availability is supported by evidence rather than a “backup completed” badge. diff --git a/docs/STORYBOOK_INVENTORY.md b/docs/STORYBOOK_INVENTORY.md new file mode 100644 index 0000000..191f13a --- /dev/null +++ b/docs/STORYBOOK_INVENTORY.md @@ -0,0 +1,99 @@ +# ELUNVERA Storybook Inventory + +## Foundations + +- typography and locale samples; +- spacing, radius, elevation, and motion tokens; +- semantic state tokens: authoritative, observed, inferred, proposed, disputed, rejected, superseded; +- focus, disabled, read-only, error, warning, and success states; +- account and data-classification badges; +- exact-value and print tokens. + +## Navigation and layout + +- `GlobalNavigation`; +- `WorkspaceSwitcher`; +- `TemporalLensBar`; +- `ThreeBandAccountLayout`; +- `EvidenceDrawer`; +- `ContextualActionBar`; +- `ResponsiveSideSheet`. + +## Domain components + +- `AccountHeader`; +- `AccountContextBand`; +- `RelationshipStructureBand`; +- `ActionRiskBand`; +- `StakeholderTree`; +- `RelationshipGraph`; +- `RelationshipTable`; +- `TruthStatusBadge`; +- `EvidenceReferenceList`; +- `TemporalFactCard`; +- `CommitmentCard`; +- `CommitmentQueue`; +- `OpportunityStageHistory`; +- `ForecastSnapshotCard`; +- `ComplaintTimeline`; +- `OutcomeTracker`; +- `ModelClaimCard`; +- `ReviewDecisionPanel`; +- `OperationReceiptPanel`; +- `DataRightsExportPreview`. + +## Form patterns + +- time-valid relationship editor; +- opportunity stage-transition form; +- exact-money input with currency; +- evidence attachment selector; +- manual-assertion disclosure; +- conflict resolution form; +- account merge comparison; +- purpose and disclosure policy selector; +- destructive action preview. + +## Required scenes for every component + +```text +default +hover where meaningful +keyboard focus +touch interaction +loading +empty +partial +stale +conflict +access denied +offline +error +success +high zoom +reduced motion +Korean +English +print +``` + +## Event definitions + +Storybook interaction tests must emit semantic product events rather than DOM implementation details. Examples: + +```text +account_brief_opened +relationship_evidence_opened +truth_status_review_started +opportunity_stage_change_proposed +commitment_status_changed +complaint_remedy_reviewed +model_claim_reviewed +export_preview_opened +``` + +Events exclude raw names, notes, message bodies, contact details, and unrestricted tenant identifiers. + +## Accessibility evidence + +Each interactive story includes automated accessibility checks, keyboard script, expected accessible name and role, focus sequence, reduced-motion behavior, and screen-reader notes for dynamic updates. Graph stories include a synchronized structured table. diff --git a/docs/TEST_STRATEGY.md b/docs/TEST_STRATEGY.md new file mode 100644 index 0000000..8a563cb --- /dev/null +++ b/docs/TEST_STRATEGY.md @@ -0,0 +1,170 @@ +# ELUNVERA Test Strategy + +- **Document version:** 0.1 +- **Status:** Proposed quality baseline +- **Date:** 2026-08-27 + +## 1. Objective + +Testing must demonstrate product behavior, tenant and privacy boundaries, temporal correctness, scientific validity, accessibility, performance, recovery, and release reproducibility. Test counts or green status without realistic assertions are not sufficient evidence. + +## 2. Quality gates + +For ELUNVERA-owned shipped code: + +- production statement coverage: **100%**; +- production branch coverage: **100%**; +- public module, type, trait, function, method, error, and API documentation coverage: **100%**; +- skipped or ignored release tests: **0**, unless the release manifest explicitly excludes the feature; +- compiler and linter warnings: **0**; +- unresolved deprecation warnings: **0**; +- contract fixture failures: **0**. + +Generated clients and third-party code are measured separately and may not dilute production coverage. + +## 3. Test layers + +### Unit tests + +Validate domain state transitions, temporal interval operations, identifier handling, currency arithmetic, policy decisions, schema transformations, and error paths. + +### Property tests + +Generate sequences of commands and prove invariants including: + +- no overlapping active role intervals where uniqueness is required; +- account merge plus reversal preserves all source references; +- debit-like exact amounts do not change under serialization round trips; +- idempotent command replay produces one event and one aggregate version; +- stage history never disappears after correction; +- disclosure decisions are monotonic with stricter policy; +- relationship participants remain tenant-consistent. + +### Database integration tests + +Run against real PostgreSQL 18.6 or a later supported 18.x patch. Validate migrations, RLS, temporal constraints, indexes, transaction isolation, outbox atomicity, lock behavior, partition pruning, backup, and restore. + +### Contract tests + +Validate OpenAPI, AsyncAPI, CloudEvents, JSON Schema, generated clients, Problem Details, pagination cursors, idempotency, ETags, provider adapters, and backward compatibility. + +### Fuzz tests + +Target parsers, identifiers, rich text, import payloads, webhook signatures, cursor decoding, date intervals, currency input, CSV/Office exports, and event envelopes. + +### Security tests + +Cover authentication, authorization, tenant isolation, purpose escalation, IDOR, injection, SSRF, path traversal, MIME confusion, formula injection, mass assignment, replay, privilege escalation, malicious redirects, and secret leakage. + +### Model and scientific tests + +A model feature cannot pass through ordinary snapshot tests alone. Required evidence includes: + +- defined target outcome and population; +- gold or independently reviewed evidence set; +- true-parameter recovery for synthetic models where applicable; +- calibration and uncertainty evaluation; +- subgroup and context-specific error analysis; +- temporal validation and leakage-safe split; +- baseline and ablation comparisons; +- unsupported-claim rate; +- independent reviewer agreement; +- CPU/GPU parity for Rust numerical kernels; +- model/provider/prompt repeatability bounds. + +Arbitrary weights and rule-of-thumb thresholds are prohibited. + +### UX and accessibility tests + +- keyboard-only journeys; +- screen-reader semantics; +- focus order and restoration; +- touch target and mobile viewport; +- high zoom and text reflow; +- reduced-motion preference; +- Korean and English copy expansion; +- loading, empty, partial, stale, conflict, denied, offline, and error states; +- exact-value tables and print/PDF output for charts; +- Storybook interaction and accessibility tests. + +### End-to-end buyer journeys + +1. Create an account, add stakeholders, record a relationship, and verify history. +2. Record an interaction and commitment, change status, and inspect evidence. +3. Progress an opportunity with optimistic concurrency and immutable stage history. +4. Receive a duplicate connector event and prove one canonical fact. +5. Resolve a complaint and connect remedy, outcome, and follow-up. +6. Submit a data-access case and inspect a purpose-limited export. +7. Attempt cross-tenant reads, writes, search, graph traversal, export, and model access. +8. Restore the system and prove data, outbox, projection, and key consistency. + +## 4. Realistic fixtures + +Fixtures represent multi-stakeholder B2B relationships, account hierarchy, role changes, former employees, multiple opportunities, delayed interactions, conflicting commitments, complaints, multiple currencies, duplicated events, malformed imports, and multilingual text. Names and organizations are synthetic. + +Synthetic data is labeled and never used as evidence of customer accuracy or product-market fit. + +## 5. Temporal validation + +Tests use both business time and recorded time. Cases include: + +- a later document describing an earlier event; +- a corrected stakeholder role; +- a backdated stage transition recorded today; +- a knowledge-cutoff query that must exclude later evidence; +- overlapping intervals rejected by constraint; +- daylight-saving and timezone boundaries; +- incomplete or uncertain intervals; +- merge and split history at different recorded times. + +## 6. Performance and load + +A k6 or equivalent end-to-end suite exercises asynchronous and synchronous workflows. Initial engineering acceptance targets are: + +| Workload | Target | +|---|---:| +| account summary read | p95 ≤ 300 ms at 200 concurrent users | +| account timeline, 1,000 entries | p95 ≤ 700 ms | +| relationship neighborhood, depth 2 | p95 ≤ 1.5 s with bounded result set | +| optimistic update | p95 ≤ 500 ms | +| event ingestion | sustained 1,000 events/s per deployment profile | +| queue admission under saturation | bounded response with no silent drop | +| export request | acknowledgement ≤ 500 ms; asynchronous completion | + +These are release targets, not current performance claims. Tests record hardware, dataset size, connection pools, cache state, and commit SHA. + +## 7. Recovery testing + +- point-in-time restore into an isolated environment; +- active and predecessor key availability; +- schema compatibility and migration replay; +- outbox/inbox deduplication after restore; +- projection rebuild from canonical data; +- object-store artifact reconciliation; +- lost worker and connection interruption; +- partial provider outage; +- rollback or forward-fix decision evidence. + +## 8. CI structure + +Suggested required checks: + +```text +Contract and documentation validation +Rust format, lint, unit, property, and doc tests +PostgreSQL integration and migration rehearsal +Frontend lint, typecheck, unit, Storybook, and E2E +Coverage and documentation gate +SAST and secret scan +Dependency review and vulnerability scan +CodeQL or equivalent semantic analysis +Fuzz smoke and scheduled deep fuzz +Supply-chain SBOM and provenance +Production-readiness evidence +``` + +Every check runs on the exact PR head or merge-result tree specified by branch policy. Prior-head success is not current evidence. + +## 9. Test-evidence manifest + +A release manifest records command, environment, commit, dependency lock hash, database version, browser version, test counts, coverage denominators, skipped tests, benchmark profile, artifact hashes, and reviewer identity. diff --git a/docs/THREAT_MODEL.md b/docs/THREAT_MODEL.md new file mode 100644 index 0000000..a116aa2 --- /dev/null +++ b/docs/THREAT_MODEL.md @@ -0,0 +1,132 @@ +# ELUNVERA Threat Model + +- **Document version:** 0.1 +- **Status:** Proposed threat-model baseline +- **Date:** 2026-08-27 + +## 1. Scope + +This threat model covers the proposed ELUNVERA web applications, Rust API and workers, PostgreSQL system of record, object storage, search and graph projections, Keyverse identity integration, CWL adapters, event transport, exports, and model workflows. + +## 2. Protected assets + +- tenant and workspace isolation; +- customer and stakeholder identities; +- relationship and account history; +- opportunity values, forecasts, strategy, and commitments; +- complaint narratives and remedies; +- contact points and communication preferences; +- model prompts, claims, evaluation evidence, and configuration; +- audit, legal hold, data-rights, and disposition records; +- integration credentials and provider mappings; +- release artifacts and database migrations. + +## 3. Adversaries and failure actors + +- unauthenticated internet attacker; +- compromised tenant user; +- malicious tenant administrator; +- overprivileged support operator; +- compromised service principal or connector; +- malicious or buggy provider webhook; +- hostile imported file or rich-text content; +- indirect prompt injection embedded in customer content; +- supply-chain attacker; +- accidental operator or migration error; +- noisy tenant causing resource exhaustion; +- insider attempting covert export or history alteration. + +## 4. Trust boundaries + +```mermaid +flowchart LR + Browser[User browser] --> Edge[Ingress and web edge] + Edge --> API[Rust API] + API --> DB[(PostgreSQL SoR)] + API --> Queue[Durable job and outbox] + Queue --> Worker[Rust workers] + Worker --> Object[(Object storage)] + Worker --> Projection[(Search / graph projection)] + API --> Keyverse[Keyverse] + Worker --> CWL[CWL capability adapters] + CWL --> External[Customer and provider systems] +``` + +Every arrow crossing an organizational or runtime boundary requires authenticated identity, schema validation, bounded input, timeout, audit receipt, and explicit error handling. + +## 5. Principal abuse cases + +| ID | Threat | Security property | Required mitigation | +|---|---|---|---| +| TM-01 | Guess another tenant’s account ID | Confidentiality | tenant-bound authorization plus RLS; non-disclosing response | +| TM-02 | Modify a stale opportunity over a newer stage | Integrity | ETag, `If-Match`, temporal history, operation receipt | +| TM-03 | Replay a webhook or command | Integrity | signature, timestamp window, inbox deduplication, idempotency key | +| TM-04 | Inject SQL/Cypher/search syntax | Integrity and availability | typed queries, parameterization, allowlisted traversal, depth bounds | +| TM-05 | Upload executable or disguised content | Confidentiality and availability | signature-based MIME validation, quarantine, no execution or fetch | +| TM-06 | Prompt content asks model to leak data or call tools | Confidentiality | instruction/observation separation, bounded tools, policy evaluator | +| TM-07 | LLM invents stakeholder influence and system applies it | Integrity and fairness | separate model claim, evidence link, human review, no direct mutation | +| TM-08 | Support operator exports all tenant data | Confidentiality | purpose, maker-checker, time-bound role, export receipt, anomaly alert | +| TM-09 | Merge two parties incorrectly and erase history | Integrity | dry-run, evidence comparison, reversible mapping, immutable receipt | +| TM-10 | Delete data under legal hold | Compliance and integrity | hold check in DB and domain layer, fail closed, audit exception | +| TM-11 | Noisy tenant exhausts queue or DB pool | Availability | quotas, fair scheduling, pool partitioning, backpressure | +| TM-12 | Malicious migration removes isolation | Confidentiality | migration review, clean and upgrade rehearsal, policy tests | +| TM-13 | Dependency or CI action compromise | Integrity | exact pins, SBOM, provenance, signatures, minimal workflow permission | +| TM-14 | Graph projection gains authority over canonical data | Integrity | read-model-only credentials, rebuildability, command prohibition | +| TM-15 | Timing or error text reveals cross-tenant existence | Confidentiality | normalized not-found behavior, bounded timing, safe errors | +| TM-16 | Export formula executes in spreadsheet | Integrity | formula neutralization and format-specific security tests | +| TM-17 | Backup exists but keys or schema cannot restore it | Availability | scheduled restore rehearsal with key and migration verification | +| TM-18 | Provider outage causes duplicate external actions | Integrity | provider-sticky operation identity, command journal, reconciliation | + +## 6. STRIDE summary + +### Spoofing + +Mitigated by Keyverse OIDC validation, phishing-resistant authentication profiles, service identity, short-lived credentials, and SCIM lifecycle. + +### Tampering + +Mitigated by optimistic concurrency, append-only history, source hashes, transactional outbox, signed artifacts, database constraints, and immutable audit. + +### Repudiation + +Mitigated by operation, export, review, merge, disposition, model, and provider receipts linked by correlation and causation identifiers. + +### Information disclosure + +Mitigated by tenant enforcement, purpose-aware field selection, disclosure policy, encryption, provider allowlists, and telemetry minimization. + +### Denial of service + +Mitigated by bounded input, query budgets, fair queues, asynchronous jobs, circuit breakers, rate limits, and capacity telemetry. + +### Elevation of privilege + +Mitigated by immutable verified context, no caller-supplied authority, least-privilege service accounts, maker-checker approval, and tool capability checks. + +## 7. Model-specific threats + +- indirect prompt injection; +- unsupported claims presented as facts; +- training-data or provider leakage; +- model drift and changed output contracts; +- biased relationship or opportunity predictions; +- confidence miscalibration; +- provider fallback changing data residency; +- unbounded recursive agent work; +- model output schema bypass; +- cached context crossing tenants. + +All model paths use strict schema validation, evidence grounding, provider and region policy, bounded recursion, independent verification for consequential output, and tenant-bound caches. + +## 8. Residual-risk governance + +Every accepted residual risk records owner, rationale, scope, expiration, compensating control, monitoring signal, and re-review date. “Accepted” is not equivalent to “fixed” or “safe.” Expired acceptance fails the release or operation gate until reviewed. + +## 9. Verification cadence + +- threat model reviewed on every trust-boundary or high-impact data-flow change; +- dependency and provider threat review on every major version; +- tabletop exercise before GA and at least annually; +- external penetration test before processing production customer data; +- prompt-injection and tenant-isolation regression on every release candidate; +- backup, restore, and credential-rotation rehearsal on a scheduled cadence. diff --git a/docs/TRD.md b/docs/TRD.md new file mode 100644 index 0000000..2bd4efa --- /dev/null +++ b/docs/TRD.md @@ -0,0 +1,342 @@ +# ELUNVERA Technical Requirements Document + +- **Document version:** 0.1 +- **Status:** Proposed technical baseline +- **Date:** 2026-08-27 + +## 1. Technical objective + +Build a Rust-first, tenant-isolated, evidence-centered CRM that preserves relationship and commercial history, integrates with CWL products through versioned contracts, and supports deterministic operation without requiring an LLM or external SaaS provider for core transaction paths. + +## 2. Architectural style + +ELUNVERA begins as a **modular monolith with independently testable modules**, one PostgreSQL system of record, durable background workers, and a transactional outbox. Clear domain ports permit later extraction only when workload, release cadence, regulatory boundary, or independent ownership justifies a service split. + +A microservice-per-noun design is explicitly rejected. It would create distributed transactions before domain boundaries and workloads are proven. + +## 3. Technology baseline + +| Layer | Baseline | Requirement | +|---|---|---| +| Backend | Rust | Stable compiler pinned in repository; async, multithreaded runtime | +| HTTP | Axum or an equivalent reviewed Rust framework | OpenAPI-generated/validated contract and structured errors | +| Database | PostgreSQL 18.6+ within supported 18.x | RLS, temporal constraints, UUIDv7, partitioning, logical backup/restore | +| Web | React/Next.js TypeScript | Server-rendered where appropriate; accessible progressive enhancement | +| Contracts | OpenAPI 3.2.0, AsyncAPI 3.1.0, JSON Schema 2020-12 | Generated clients and conformance fixtures | +| Events | CloudEvents 1.0 envelope | At-least-once delivery and consumer idempotency | +| Identity | Keyverse OIDC/OAuth 2.1 and SCIM | No local password authority | +| Telemetry | OpenTelemetry | No raw customer content or high-cardinality PII attributes | +| Packaging | OCI images and generated SDK packages | Digest-pinned dependencies, SBOM, provenance, signatures | +| Local runtime | Compose-compatible Podman/Colima/Docker | K8s portability without requiring K8s for development | + +Exact dependency versions are selected and lock-pinned in implementation PRs. “Latest” is not a reproducible dependency specification. + +## 4. Repository target structure + +```text +ELUNVERA/ +├── apps/ +│ ├── elunvera_api/ +│ ├── elunvera_worker/ +│ ├── elunvera_web/ +│ └── elunvera_admin/ +├── crates/ +│ ├── domain_contracts/ +│ ├── authorization_context/ +│ ├── account_registry/ +│ ├── party_registry/ +│ ├── relationship_registry/ +│ ├── interaction_timeline/ +│ ├── commitment_registry/ +│ ├── opportunity_management/ +│ ├── customer_outcomes/ +│ ├── complaint_management/ +│ ├── privacy_rights/ +│ ├── audit_provenance/ +│ ├── integration_outbox/ +│ ├── search_projection/ +│ └── model_evidence/ +├── integrations/ +│ └── cwl/ +│ ├── keyverse_adapter/ +│ ├── naruon_adapter/ +│ ├── contextual_orchestrator_adapter/ +│ ├── semantic_data_portal_adapter/ +│ ├── scopeweave_adapter/ +│ └── billing_control_plane_adapter/ +├── packages/ +│ ├── typescript_sdk/ +│ └── design_tokens/ +├── database/ +│ ├── migrations/ +│ └── fixtures/ +├── schemas/ +├── tests/ +│ ├── contract/ +│ ├── integration/ +│ ├── property/ +│ ├── fuzz/ +│ ├── security/ +│ ├── performance/ +│ └── e2e/ +├── docs/ +└── infrastructure/ +``` + +This is a target layout, not a statement that these components exist. + +## 5. Domain modules + +### 5.1 Authorization context + +Consumes a verified Keyverse token and produces an immutable request context: + +```text +actor_reference +tenant_reference +workspace_reference +role_set +purpose_code +decision_reference +correlation_id +authentication_strength +token_issued_at +token_expires_at +``` + +No domain function accepts a caller-supplied tenant ID as authority. The verified context supplies tenant scope. + +### 5.2 Account registry + +Owns commercial account identity, lifecycle, hierarchy references, role assignments, duplicate review, merge/split receipts, and current account projection. + +### 5.3 Party registry + +Owns tenant-scoped party records for persons, organizations, and groups, plus names, identifiers, contact points, and source mappings. It must preserve local identity without asserting that different tenants refer to the same real-world party. + +### 5.4 Relationship registry + +Owns first-class, time-valid party and account relations. It distinguishes authoritative, observed, inferred, proposed, rejected, and superseded facts. + +### 5.5 Interaction timeline + +Owns manual interactions and normalized metadata projections. Raw external messages remain with the source provider or customer-controlled system. + +### 5.6 Commitment registry + +Owns relationship commitments and their state transitions. General project execution may be delegated to ScopeWeave through an external work reference. + +### 5.7 Opportunity management + +Owns opportunity facts, sales-process versions, stages, transitions, stakeholders, values, forecast snapshots, assumptions, products/offerings by reference, and outcome linkage. + +### 5.8 Customer outcomes and complaints + +Owns desired outcomes, observations, complaint lifecycle, remedies, satisfaction measurement references, and released relationship assessments. + +### 5.9 Privacy rights + +Owns purpose registry, communication preferences, consent or other processing-basis references, data-rights cases, retention decisions, legal hold, disposition receipts, and export manifests. + +### 5.10 Audit and provenance + +Owns immutable audit events, source receipts, model claims, evidence links, event publication receipts, and data-transformation lineage. + +## 6. Persistence requirements + +### 6.1 Canonical relational store + +- PostgreSQL is the authoritative store. +- Canonical domain data is normalized to 3NF. +- JSONB is restricted to immutable provider payload metadata, schema-versioned extension values, or diagnostic context that does not determine money, authorization, tenancy, stage, relationship truth, or model score. +- Graph, search, vector, analytics, and dashboard stores are rebuildable projections. +- External system identifiers are isolated in mapping tables. + +### 6.2 Identifiers + +- Use UUIDv7 for externally visible aggregate identifiers. +- Never expose sequential database identifiers. +- Do not infer creation time for authorization or business logic from UUID ordering. +- Source event identity is `(source_authority, source_event_key)`. + +### 6.3 Bitemporal facts + +Time-valid facts carry: + +```text +valid_time tstzrange +recorded_time tstzrange +``` + +PostgreSQL 18 temporal constraints or equivalent exclusion constraints prevent overlapping active intervals where the domain requires uniqueness. + +`valid_time` means when the fact was true in the business domain. `recorded_time` means when ELUNVERA believed or stored that version. + +### 6.4 Monetary values + +- Store money as exact decimal numeric plus currency code. +- Store quantity, unit, rate, and amount separately. +- Preserve every value and forecast snapshot; corrections append reversal/replacement facts. +- Never use `f32` or `f64` for monetary calculations. + +### 6.5 Partition and hot-key policy + +Partition only with measured evidence. The release benchmark shall evaluate: + +- hash partitioning by tenant for high-volume audit and interaction tables; +- range subpartitioning by recorded month; +- isolation of very large tenants; +- index locality for account timelines; +- queue and outbox contention; +- vacuum and retention behavior. + +A tenant ID alone must not create a single unbounded hot partition. + +## 7. Transaction requirements + +- Aggregate state and its outbox event commit in the same database transaction. +- Optimistic concurrency uses explicit version or ETag. +- Commands require an idempotency key. +- A successful response includes an operation receipt and resulting aggregate version. +- Retries with the same key and payload return the same result. +- Reuse of a key with a different payload fails closed. +- Every ingestion batch has item-level results; one malformed item does not silently discard neighboring items. + +## 8. HTTP requirements + +- Base path: `/v1`. +- Content type: JSON unless an explicit export/import media type is defined. +- Errors: RFC 9457 Problem Details. +- Pagination: opaque cursor, deterministic order, bounded page size. +- Conditional writes: ETag and `If-Match` for user-editable aggregates. +- Request body and upload limits enforced before full allocation. +- Long operations return `202 Accepted` and a durable job reference. +- Cancellation is explicit and records whether work was never started, cancelled, or completed before cancellation. + +## 9. Event requirements + +Every domain event uses a CloudEvents envelope and includes: + +```text +specversion +id +source +type +subject +time +datacontenttype +tenantref +correlationid +causationid +provenanceref +data_classification +schema_revision +``` + +Events contain opaque references and minimum necessary data. Consumers retrieve authorized details from the owning API. + +## 10. Search and relationship projection + +### Search channels + +- exact identifier and contact lookup; +- lexical search; +- structured filters; +- semantic retrieval over approved semantic units; +- graph-neighborhood retrieval; +- recency and authoritative-source channels. + +RankWeave may fuse ranked results. Raw similarity scores from different embedding spaces are never averaged. Every vector has an `embedding_space_id`, model revision, input role, origin, and creation time. + +### Graph projection + +The normalized relationship store is authoritative. A graph projection may be rebuilt for variable-depth relationship and organization queries. Inferred LineageWeave edges are visibly distinct and may not be promoted without review. + +## 11. AI and model requirements + +- Core CRUD, search filters, authorization, exports, and workflow state do not require an LLM. +- All LLM requests go through `contextual-orchestrator`. +- Prompt, provider, model, reasoning level, tool access, source references, result schema, and verification status are recorded. +- Source documents are untrusted content and cannot alter system policy or tool permissions. +- Outputs use strict JSON Schema. +- Unsupported claims are removed or marked unsupported. +- An assistant action is separated into proposal, authorization, execution, observation, and verification. +- Model fallback must preserve operation capability; chat, embeddings, image, audio, and structured outputs are not interchangeable. + +## 12. Numerical model requirements + +Relationship health, opportunity risk, satisfaction, forecast probability, and influence estimation are numerical products, not UI decorations. + +Any released numerical model shall: + +- have a stated estimand and decision use; +- define population, sampling design, error target, and failure denominator; +- use Rust production arithmetic; +- include CPU reference and GPU parity where GPU is used; +- test true-parameter recovery, bias, RMSE, interval coverage, calibration, and drift; +- account for multilevel, multiple-membership, and longitudinal structure where applicable; +- report uncertainty and allow abstention; +- preserve model, data, feature, prompt, and code lineage; +- avoid rule-of-thumb weights. + +## 13. Integration requirements + +Each integration implements narrow capability ports. Examples: + +```text +IdentityVerificationPort +InteractionObservationPort +MessageThreadReferencePort +WorkItemReferencePort +OntologyReferencePort +RetrievalFusionPort +ModelExecutionPort +BillingEntitlementPort +``` + +A connector capability manifest declares read, propose, write, delete, export, webhook, and synchronization support. Provider-specific fields remain in adapter and mapping tables. + +## 14. Security requirements + +- Keyverse JWT signature, issuer, audience, expiry, token type, and authorization context validation. +- PostgreSQL RLS or equivalent enforced isolation. +- Dedicated runtime role with `NOSUPERUSER`, `NOBYPASSRLS`, and minimum privileges. +- Secrets resolved from approved secret management, never repository or database plaintext. +- Egress allowlist with DNS rebinding, method, host, port, size, timeout, and redirect controls. +- Structured logs redact tokens and minimize PII but do not destructively alter source records. +- Exports require purpose, field policy, bounded scope, and a signed receipt. +- Model and connector content is untrusted. + +## 15. Frontend requirements + +- Design tokens are the only source for repeated spacing, typography, color, elevation, and motion. +- Shared components are documented in Storybook with loading, empty, error, access-denied, stale, conflict, partial-data, and offline states. +- Figma file ID and component mapping are recorded before production UI acceptance. +- Account overview uses three horizontal bands: context, relationships, and action. +- A generic floating chat box is not the primary interface; evidence-grounded assistance is embedded in the active account or workflow context. +- Every write action has pending, success, retryable failure, and conflict states. +- No internal repository or service name appears in customer-facing copy. + +## 16. Operations requirements + +- Separate liveness, startup, and readiness probes. +- Readiness fails when required storage, migration compatibility, authorization material, or critical queues are unavailable. +- Graceful drain stops new work and bounds in-flight completion. +- OpenTelemetry traces, metrics, and logs use low-cardinality dimensions. +- SLOs cover interactive API, background jobs, event projection, connectors, and data-rights workflows. +- Backup, restore, key availability, and projection rebuild are rehearsed. +- Release and rollback are versioned and observable. + +## 17. Build and supply-chain requirements + +- Lock dependencies and verify lock freshness. +- Pin GitHub Actions by full commit SHA. +- Generate SPDX SBOM and SLSA-compatible provenance. +- Sign release artifacts and verify before promotion. +- Scan source, dependencies, images, IaC, and secrets. +- Do not run untrusted build hooks during dependency materialization. +- Reproducible build comparison is required for GA candidate artifacts. + +## 18. Definition of done for a technical slice + +A slice is complete only when its user behavior, domain model, API/event contract, migration, authorization, tests, telemetry, rollback, documentation, ADR impact, and product-gap status are consistent and independently reviewable. diff --git a/docs/UML.md b/docs/UML.md new file mode 100644 index 0000000..24c03a3 --- /dev/null +++ b/docs/UML.md @@ -0,0 +1,115 @@ +# ELUNVERA UML and Behavioral Models + +## 1. Component model + +```mermaid +flowchart TB + Web[ELUNVERA Web] --> API[ELUNVERA API] + Admin[Admin Console] --> API + API --> Auth[Authorization Context] + API --> Accounts[Account and Party Modules] + API --> Relations[Relationship Module] + API --> Commercial[Opportunity and Commitment Modules] + API --> Outcomes[Outcome and Complaint Modules] + API --> Privacy[Privacy and Rights Module] + Accounts --> DB[(PostgreSQL)] + Relations --> DB + Commercial --> DB + Outcomes --> DB + Privacy --> DB + API --> Outbox[Transactional Outbox] + Outbox --> Worker[Worker] + Worker --> Projection[Search and Graph Read Models] + Worker --> Adapters[CWL Capability Adapters] +``` + +## 2. Account aggregate sequence + +```mermaid +sequenceDiagram + actor User + participant Web + participant API + participant Policy + participant DB + participant Outbox + + User->>Web: Save account change + Web->>API: PATCH + If-Match + Idempotency-Key + API->>Policy: authorize(context, purpose, fields) + Policy-->>API: permit + field policy + API->>DB: begin transaction + API->>DB: verify version and apply temporal fact + API->>Outbox: append account.changed event + API->>DB: commit + API-->>Web: operation receipt + new ETag +``` + +## 3. Model-claim review sequence + +```mermaid +sequenceDiagram + participant Worker + participant Orchestrator as contextual-orchestrator + participant DB + actor Reviewer + + Worker->>Orchestrator: evidence bundle + strict schema + Orchestrator-->>Worker: proposed claim + uncertainty + trace + Worker->>DB: store model_claim(proposed) + Reviewer->>DB: read claim and evidence + Reviewer->>DB: record review decision + Note over Reviewer,DB: A separate domain command is required to change authoritative facts +``` + +## 4. Opportunity state model + +```mermaid +stateDiagram-v2 + [*] --> Open + Open --> Qualified: allowed process transition + Qualified --> Validated + Validated --> Proposed + Proposed --> Negotiating + Negotiating --> Won + Negotiating --> Lost + Open --> Disqualified + Qualified --> Disqualified + Validated --> Disqualified + Won --> [*] + Lost --> [*] + Disqualified --> [*] +``` + +The actual stages and allowed transitions are versioned per tenant. This diagram is an illustrative default, not a hard-coded sales methodology. + +## 5. Complaint state model + +```mermaid +stateDiagram-v2 + [*] --> Received + Received --> Acknowledged + Acknowledged --> Investigating + Investigating --> RemedyProposed + RemedyProposed --> RemedyDelivered + RemedyDelivered --> FollowUp + FollowUp --> Closed + Received --> Withdrawn + Investigating --> Withdrawn +``` + +## 6. Truth-status state model + +```mermaid +stateDiagram-v2 + Proposed --> ReviewedInference: accepted as inference + Proposed --> Rejected + Observed --> Superseded + Authoritative --> Superseded + ReviewedInference --> Superseded + Observed --> Disputed + Authoritative --> Disputed + Disputed --> Superseded +``` + +No state transition automatically converts an inference into an authoritative source fact. diff --git a/docs/USER_STORIES.md b/docs/USER_STORIES.md new file mode 100644 index 0000000..409fec4 --- /dev/null +++ b/docs/USER_STORIES.md @@ -0,0 +1,37 @@ +# ELUNVERA User Stories + +## Account and relationship work + +- As an account owner, I need one current account view with historical evidence so that I can prepare without searching multiple systems. +- As a new account owner, I need to see former stakeholders, prior commitments, and unresolved assumptions so that handover does not erase relationship history. +- As a customer-success manager, I need desired outcomes and observed outcomes separated so that activity is not mistaken for customer value. +- As a sales leader, I need stage history and forecast assumptions preserved so that pipeline review is auditable. +- As an account-team member, I need to understand which internal colleague owns each relationship so that customers receive coordinated communication. +- As a privacy reviewer, I need disclosure decisions by purpose and relationship context so that useful information is protected without disabling work. + +## Evidence and correction + +- As a user, I need to open the evidence behind a relationship claim so that I can judge whether it is current and defensible. +- As a user, I need to correct an inferred role without deleting its source so that future models and reviewers can understand the disagreement. +- As an administrator, I need duplicate-account merge previews and receipts so that consolidation is reversible and accountable. +- As an auditor, I need to see who changed an opportunity, why, and from which prior version so that the commercial record is trustworthy. + +## Commitments and action + +- As an account manager, I need commitments connected to interactions and outcomes so that promises are not lost in notes. +- As a user, I need confirmed, tentative, and desired commitments distinguished so that a weak intention does not override a firm promise. +- As an operations user, I need long-running imports and exports to continue after I leave the page so that work is reliable. +- As a user, I need an unavailable integration described in customer language and a recovery action so that internal architecture does not leak into the interface. + +## Complaints and satisfaction + +- As a complaint owner, I need intake, investigation, remedy, customer response, and follow-up in one case so that service recovery is complete. +- As a manager, I need complaint recurrence linked to account and outcome context so that systemic problems are visible. +- As a research or quality user, I need satisfaction instruments and scores versioned with evidence so that opaque “health scores” are not substituted for measurement. + +## Administration and governance + +- As a tenant administrator, I need versioned sales processes and relationship taxonomies so that changes do not rewrite historical interpretation. +- As a security administrator, I need service principals and connector capabilities scoped to purpose so that integrations cannot read the whole tenant. +- As a data subject or authorized representative, I need a reproducible export and correction workflow so that rights can be fulfilled transparently. +- As a release reviewer, I need exact-head test, security, migration, and supply-chain evidence so that a green predecessor is not mistaken for current proof. diff --git a/docs/USE_CASES.md b/docs/USE_CASES.md new file mode 100644 index 0000000..c050cb4 --- /dev/null +++ b/docs/USE_CASES.md @@ -0,0 +1,69 @@ +# ELUNVERA Use Cases + +## UC-01 Prepare for a customer meeting + +**Actor:** Account owner +**Preconditions:** Verified tenant access and account-management purpose. +**Flow:** Open account → apply current temporal lens → review context, relationships, commitments, opportunities, complaints, and recent changes → open evidence for consequential claims → generate a bounded meeting brief → approve export. +**Postcondition:** Brief manifest and access receipt exist; no source system is mutated. + +## UC-02 Record and revise a stakeholder relationship + +**Actor:** Account-team member +**Flow:** Select parties → choose versioned relationship type → enter valid interval and account context → link evidence or mark manual assertion → save with idempotency key → later close or correct interval through a new version. +**Exceptions:** Cross-tenant party, overlapping exclusive role, stale ETag, insufficient purpose. +**Postcondition:** Historical relationship remains queryable. + +## UC-03 Progress an opportunity + +**Actor:** Account executive +**Flow:** Review current process version → propose stage transition → enter effective time, reason, evidence, and changed assumptions → server validates allowed transition → commit opportunity and outbox event atomically. +**Postcondition:** Prior stage and forecast snapshots are immutable. + +## UC-04 Resolve conflicting roles + +**Actor:** Account owner or data steward +**Flow:** System displays two current role claims → compare sources and temporal intervals → accept, correct, reject, or preserve both as context-specific → record review decision. +**Postcondition:** Truth status changes are explicit; source evidence remains. + +## UC-05 Import external CRM data + +**Actor:** Tenant administrator +**Flow:** Register provider and mapping → upload or connect bounded source → dry-run validation and duplicate report → approve batch → item-level idempotent ingestion → reconcile counts and errors. +**Postcondition:** Provider IDs live only in mapping records; malformed items are reported rather than silently dropped. + +## UC-06 Merge duplicate accounts + +**Actor:** Data steward with maker-checker approval +**Flow:** Request dry-run → compare fields, relationships, interactions, opportunities, privacy policies, and external mappings → choose canonical survivor without deleting source identities → independent approval → execute → verify projections. +**Postcondition:** Merge receipt supports reversal or split. + +## UC-07 Protect a commitment + +**Actor:** Account manager +**Flow:** Record commitment with owner, beneficiary, status, due interval, and evidence → observe updates from calendar/email by reference → review conflict → confirm action or delegate execution to ScopeWeave. +**Postcondition:** ELUNVERA owns commitment truth, not external task execution. + +## UC-08 Manage a complaint + +**Actor:** Complaint owner +**Flow:** Record complaint and channel → classify impact without arbitrary severity score → investigate evidence → propose remedy → record customer response → verify follow-up and outcome. +**Postcondition:** Complaint lifecycle is linked to account, interactions, outcomes, and corrective action. + +## UC-09 Review a model claim + +**Actor:** Authorized human reviewer +**Flow:** Open proposed claim → inspect model, prompt, evidence, uncertainty, subgroup limitations, and validation status → accept as reviewed inference, reject, or request more evidence. +**Postcondition:** Review cannot convert the claim into a different underlying fact without a separate domain command. + +## UC-10 Fulfill a data-access request + +**Actor:** Privacy operations user +**Flow:** Verify requester → scope identities and tenants → collect authorized fields and sources → review exclusions → generate encrypted export → deliver with expiration → record receipt. +**Postcondition:** The case preserves the basis for inclusion and exclusion. + +## UC-11 Restore after an incident + +**Actor:** Operations engineer +**Flow:** Create isolated environment → restore database and object artifacts → load correct keys and release manifest → replay migrations and outbox safely → rebuild projections → run integrity and tenant tests → approve service return. +**Postcondition:** Restoration evidence is retained and gaps become remediation items. diff --git a/docs/UX_SPEC.md b/docs/UX_SPEC.md new file mode 100644 index 0000000..e4da194 --- /dev/null +++ b/docs/UX_SPEC.md @@ -0,0 +1,171 @@ +# ELUNVERA UX Specification + +- **Document version:** 0.1 +- **Status:** Proposed interaction baseline +- **Date:** 2026-08-27 + +## 1. Experience objective + +A customer-facing professional should understand an account, the people around it, what changed, what is at risk, and the next defensible action without reconstructing context from multiple applications. + +The interface must expose evidence and uncertainty without turning the user into a graph-database operator or revealing internal CWL service boundaries. + +## 2. Information architecture + +```text +Home +Accounts +Relationships +Opportunities +Commitments +Complaints and Outcomes +Search +Reports +Administration +``` + +Email, calendar, files, projects, billing, and identity remain external products surfaced through integrated evidence or action references, not duplicated navigation hierarchies. + +## 3. Account overview: three horizontal bands + +The primary account page uses three full-width bands. + +### Band 1 — Account context + +- account identity, lifecycle, segment, owner, hierarchy, and current purpose; +- key customer outcomes and active commercial scope; +- last verified change and data freshness; +- compact actions: prepare interaction, add evidence, review duplicate. + +### Band 2 — Relationship structure + +- organization and stakeholder hierarchy; +- internal account team; +- time-valid roles and relationships; +- current, former, inferred, proposed, and disputed status; +- evidence and confidence drawer; +- exact-value/table alternative to any graph. + +### Band 3 — Action and risk + +- open commitments ordered by due state and consequence; +- opportunity decisions and unresolved assumptions; +- complaint recovery actions; +- recent changes requiring review; +- proposed next actions with evidence and human approval boundary. + +The bands remain visible as an ordered vertical flow on smaller screens. They are not three equal dashboard cards. + +## 4. Design principles + +### Evidence near the claim + +Every claim, stage change, recommendation, and score exposes source, recorded time, valid time, truth status, model status, and reviewer. + +### Correct by exception + +The product resolves routine context where evidence is sufficient and offers an obvious correction path. It avoids repeated disambiguation prompts but never hides uncertainty or performs irreversible action without approval. + +### Next-action copy + +Messages use customer language: + +- “Review two conflicting stakeholder roles” rather than “relationship projection error.” +- “Reconnect the calendar source to update this commitment” rather than “naruon adapter unavailable.” +- “Refresh and compare changes before saving” rather than “optimistic lock exception.” + +### Stable spatial memory + +Navigation, filters, evidence drawers, and action placement remain consistent across accounts, opportunities, complaints, and commitments. + +## 5. Core components + +```text +AccountHeader +ContextBand +RelationshipBand +ActionBand +StakeholderTree +RelationshipGraph +RelationshipTable +Timeline +EvidenceDrawer +TruthStatusBadge +TemporalLens +CommitmentQueue +OpportunityStageHistory +ForecastEvidencePanel +ComplaintRecoveryPanel +OutcomeTracker +ModelClaimCard +ConflictResolutionPanel +DataRightsCasePanel +OperationReceipt +``` + +Each component has loading, empty, partial, stale, access-denied, conflict, offline, error, and completed states. + +## 6. Interaction rules + +- No destructive action appears as a primary button without consequence preview. +- Stage transitions require effective time, reason, and evidence or explicit manual assertion. +- Account merge begins with a dry-run comparison and ends with a reversible receipt. +- Model proposals cannot be accepted through an unlabeled generic “Save.” +- Long jobs remain navigable after leaving the page. +- Filters and temporal lens are reflected in the URL without exposing restricted data. +- Back navigation restores scroll, selection, and expanded evidence state. +- Empty states explain required permission or next action. + +## 7. Search experience + +Search accepts business language and structured filters. Results show: + +- why the item matched; +- authority and truth status; +- effective and recorded time; +- account and relationship context; +- access-limited field omissions; +- source evidence; +- the action available from the result. + +A generative answer is accompanied by a result set and claim-by-claim evidence. Search never fabricates a missing fact to produce fluent prose. + +## 8. Accessibility + +Target: WCAG 2.2 AA. + +- all workflows keyboard operable; +- visible focus and logical order; +- no color-only truth or risk state; +- graph has structured table and text summary; +- charts provide exact-value table and export; +- 200% zoom without two-dimensional scrolling for ordinary content; +- touch targets meet target-size guidance; +- motion respects reduced-motion preference; +- live regions are limited and non-disruptive; +- drag-and-drop has button and keyboard alternatives; +- errors identify the field, cause, and recovery action. + +## 9. Internationalization + +Korean and English are first-release interface languages. Copy is not concatenated from fragments. Dates, names, addresses, currencies, time zones, honorifics, and organization order are locale-aware. The canonical data model does not assume Western given-name or organization formats. + +## 10. Responsive behavior + +- desktop: persistent navigation, three-band account flow, evidence drawer; +- tablet: collapsible navigation and contextual side sheet; +- mobile: single-column bands, bottom action sheet, compact temporal controls; +- print/PDF: account brief with evidence references and no hover dependence. + +## 11. Design system and Figma + +A Figma file is required before implementation of the production interface. Its file ID is recorded in an ADR once created. Design tokens are source-controlled and shared with Storybook. The Figma library must cover account overview, relationship exploration, opportunity review, complaint recovery, exports, all edge states, Korean/English copy, keyboard focus, and print. + +## 12. UX validation + +- task-based usability testing with account executives, account managers, customer-success users, operations administrators, and privacy/security reviewers; +- accessibility audit with automated and assistive-technology testing; +- screenshot review at desktop, tablet, and mobile breakpoints; +- performance checks for timeline and relationship visualization; +- copy review ensuring customer action language and absence of internal implementation boundaries; +- event instrumentation reviewed for privacy and semantic consistency. diff --git a/docs/VALIDATION_REPORT.md b/docs/VALIDATION_REPORT.md new file mode 100644 index 0000000..e3d0f58 --- /dev/null +++ b/docs/VALIDATION_REPORT.md @@ -0,0 +1,49 @@ +# ELUNVERA Documentation Baseline Validation Report + +- **Validation date:** 2026-08-27 +- **Scope:** Documentation, contracts, schemas, local links, and artifact integrity +- **Runtime claim:** None + +## Results + +| Check | Result | +|---|---| +| Required product and technical documents | Pass | +| ADR index and 16 ADR files | Pass | +| Markdown local-link resolution | Pass | +| Markdown code-fence balance | Pass | +| JSON parsing | Pass | +| JSON Schema Draft 2020-12 metaschema validation | Pass | +| YAML parsing | Pass | +| OpenAPI version and unique `operationId` structure | Pass | +| AsyncAPI version, channel, and operation structure | Pass | +| Placeholder-token scan | Pass | +| Obvious database two-word `snake_case` declaration check | Pass | +| Manifest SHA-256 verification | Pass after manifest generation | + +## Inventory + +- Repository files excluding `.git`: **55** +- Manifest entries excluding `manifest.json`: **54** +- ADRs excluding index: **16** +- Primary product and technical documents: PRD, TRD, Architecture, Data Model, API Contract, Security, Privacy, Threat Model, Test Strategy, Operability, UX, Roadmap, Gap Baseline +- Contract artifacts: OpenAPI 3.2.0, AsyncAPI 3.1.0, two JSON Schema Draft 2020-12 event payloads + +## Commands executed + +```text +Python JSON and JSON Schema validation +PyYAML parsing +OpenAPI/AsyncAPI structural checks +Markdown relative-link and fence checks +Placeholder and naming scans +SHA-256 manifest generation and verification +Git diff and branch-history inspection +``` + +## Limitations + +- No executable product code exists, so compilation, unit, integration, coverage, security, accessibility, load, migration, and restore claims are not available. +- No Figma file or production interface exists. +- OpenAPI and AsyncAPI were structurally validated in this environment; certification or full third-party conformance is not claimed. +- Research and standards traceability informs the design but does not establish legal compliance, certification, or product effectiveness. diff --git a/docs/WIREFRAMES.md b/docs/WIREFRAMES.md new file mode 100644 index 0000000..02f639e --- /dev/null +++ b/docs/WIREFRAMES.md @@ -0,0 +1,81 @@ +# ELUNVERA Low-Fidelity Wireframes + +These diagrams define information priority, not final visual styling. + +## Account overview — desktop + +```text +┌─────────────────────────────────────────────────────────────────────┐ +│ Global navigation Search Purpose / Profile │ +├─────────────────────────────────────────────────────────────────────┤ +│ ACME Manufacturing Active account Last verified: today │ +│ Owner · Segment · Region · Hierarchy [Prepare meeting] │ +├──────────────────── ACCOUNT CONTEXT ────────────────────────────────┤ +│ Desired outcomes │ Commercial scope │ Recent change │ Data freshness│ +├────────────────── RELATIONSHIP STRUCTURE ──────────────────────────┤ +│ Organization / stakeholder tree │ Internal account team │ +│ Relationship graph/table toggle │ Evidence and temporal lens │ +├──────────────────── ACTION AND RISK ────────────────────────────────┤ +│ Commitments │ Opportunity decisions │ Complaints │ Proposed reviews │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +## Relationship evidence drawer + +```text +┌─────────────────────────────────────┐ +│ Procurement lead │ +│ Truth: observed · Current │ +│ Valid from: 2026-08-25 │ +│ Recorded: 2026-08-27 │ +├─────────────────────────────────────┤ +│ Evidence 1 · public announcement │ +│ Evidence 2 · verified meeting │ +│ Older conflict · email signature │ +├─────────────────────────────────────┤ +│ [Correct] [Reject] [Add evidence] │ +└─────────────────────────────────────┘ +``` + +## Opportunity review + +```text +┌─────────────────────────────────────────────────────────────────────┐ +│ Opportunity · Current stage · Process version · Currency / value │ +├───────────────────────────┬─────────────────────────────────────────┤ +│ Stage history │ Decision evidence │ +│ Discover │ Stakeholders and roles │ +│ Validate │ Assumptions and unresolved questions │ +│ Propose │ Forecast snapshot with uncertainty │ +├───────────────────────────┴─────────────────────────────────────────┤ +│ [Propose stage change] [Record forecast] [Link customer outcome] │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +## Mobile account flow + +```text +[Account header] +[Context band] +[Relationship summary] +[Open relationship explorer] +[Action queue] +[Primary action sheet] +``` + +## Required edge-state frames + +```text +loading +no account data +partial connector data +stale evidence +conflicting claims +access denied +provider unavailable +offline draft +optimistic conflict +long job running +job failed with recovery +legal hold prevents deletion +``` diff --git a/docs/adr/0001-product-boundary.md b/docs/adr/0001-product-boundary.md new file mode 100644 index 0000000..b021bc0 --- /dev/null +++ b/docs/adr/0001-product-boundary.md @@ -0,0 +1,21 @@ +# ADR-0001: Own CRM truth; federate adjacent products + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +ELUNVERA needs a defensible source-of-truth boundary in the CWL ecosystem. A full-suite CRM would duplicate identity, mail, calendar, billing, project management, ontology, and model orchestration. + +## Decision + +ELUNVERA owns commercial accounts, parties within tenant context, first-class relationships, interactions metadata, commitments, opportunities, customer outcomes, complaints, satisfaction observations, privacy workflow metadata, and their audit history. Adjacent CWL products remain authoritative for their domains and integrate through explicit ports and events. + +## Consequences + +The CRM remains coherent and reusable. Integration contracts require more design work than direct database access, but prevent a distributed monolith. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0002-modular-monolith.md b/docs/adr/0002-modular-monolith.md new file mode 100644 index 0000000..ce1f4d7 --- /dev/null +++ b/docs/adr/0002-modular-monolith.md @@ -0,0 +1,21 @@ +# ADR-0002: Begin as a modular monolith + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +The domain is new, its consistency boundaries are not yet measured, and premature service decomposition would require distributed transactions. + +## Decision + +Start with independently testable Rust modules, one canonical PostgreSQL system of record, durable workers, and a transactional outbox. Extract a service only when workload, release cadence, regulatory isolation, or ownership evidence justifies it. + +## Consequences + +Strong local transactions and simpler operations are preserved. Module boundaries and contracts must still be enforced in code and tests. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0003-keyverse-identity.md b/docs/adr/0003-keyverse-identity.md new file mode 100644 index 0000000..6b8f3db --- /dev/null +++ b/docs/adr/0003-keyverse-identity.md @@ -0,0 +1,21 @@ +# ADR-0003: Use Keyverse as identity authority + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +ELUNVERA must not become another password store and must participate in CWL federation and SCIM lifecycle. + +## Decision + +Validate Keyverse OIDC/OAuth 2.1 tokens and consume SCIM lifecycle. Keep CRM party identity separate from authentication subject identity. Store opaque links, not credentials. + +## Consequences + +Authentication and workforce/customer identity remain distinct. Availability depends on token validation material and a reviewed degraded-mode policy. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0004-bitemporal-truth.md b/docs/adr/0004-bitemporal-truth.md new file mode 100644 index 0000000..c05ebb2 --- /dev/null +++ b/docs/adr/0004-bitemporal-truth.md @@ -0,0 +1,21 @@ +# ADR-0004: Represent relationship truth bitemporally + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +Customer roles, account ownership, affiliations, stages, and disclosure policy change, and late evidence may describe an earlier business event. + +## Decision + +Store business-valid and system-recorded intervals for versioned facts. Query APIs expose temporal lens and knowledge cutoff. Corrections append versions rather than overwrite history. + +## Consequences + +Audits and historical reconstruction become reliable, at the cost of more complex constraints and queries. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0005-first-class-relationships.md b/docs/adr/0005-first-class-relationships.md new file mode 100644 index 0000000..595960e --- /dev/null +++ b/docs/adr/0005-first-class-relationships.md @@ -0,0 +1,21 @@ +# ADR-0005: Make relationships first-class records + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +A bare graph edge cannot carry evidence, confidence, temporal validity, context, disclosure policy, review state, or multiple participants. + +## Decision + +Use normalized `relationship_record` and `relationship_participant` objects. Graph views are rebuildable projections of canonical records. + +## Consequences + +Context-rich relationships and multi-party roles are supported. Projection lag and relational-to-graph mapping require observability. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0006-provider-neutral-integrations.md b/docs/adr/0006-provider-neutral-integrations.md new file mode 100644 index 0000000..25b352a --- /dev/null +++ b/docs/adr/0006-provider-neutral-integrations.md @@ -0,0 +1,21 @@ +# ADR-0006: Use capability-specific integration ports + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +Providers differ materially and a generic “CRM provider” interface collapses important semantics. Provider IDs in core tables create schema coupling. + +## Decision + +Define small capability ports, preserve external object mappings in a dedicated table, journal commands, and normalize inbound assertions only after validation. + +## Consequences + +Providers can change without rewriting canonical CRM tables. More adapters and contract tests are required. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0007-purpose-aware-privacy.md b/docs/adr/0007-purpose-aware-privacy.md new file mode 100644 index 0000000..ba8ec53 --- /dev/null +++ b/docs/adr/0007-purpose-aware-privacy.md @@ -0,0 +1,21 @@ +# ADR-0007: Use purpose-aware field selection instead of universal masking + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +Authorized customer operations often require real names, contact details, and complaint context. Universal masking can make the product unusable, while unrestricted exposure violates minimization. + +## Decision + +Evaluate tenant, actor, role, purpose, data category, relationship context, disclosure policy, and legal hold. Return only allowed fields and retain decision receipts. + +## Consequences + +Operational work remains possible with auditable protection. Policy design and testing become first-class product work. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0008-ai-human-judgment.md b/docs/adr/0008-ai-human-judgment.md new file mode 100644 index 0000000..aaf83a4 --- /dev/null +++ b/docs/adr/0008-ai-human-judgment.md @@ -0,0 +1,21 @@ +# ADR-0008: Separate model claims from authoritative facts + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +LLMs can synthesize evidence but may hallucinate, inherit bias, or misinterpret context. Direct mutation would turn probabilistic output into hidden commercial truth. + +## Decision + +Route LLM work through contextual-orchestrator. Store output as `model_claim` with model, prompt, evidence, uncertainty, validation, and review status. Consequential domain changes require a separate human-authorized command. + +## Consequences + +AI assistance remains useful and inspectable. Some automation is intentionally slower because review is explicit. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0009-postgresql-system-of-record.md b/docs/adr/0009-postgresql-system-of-record.md new file mode 100644 index 0000000..dc0f5f9 --- /dev/null +++ b/docs/adr/0009-postgresql-system-of-record.md @@ -0,0 +1,21 @@ +# ADR-0009: Use PostgreSQL 18 as canonical system of record + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +CRM transactions need strong consistency, temporal constraints, row-level isolation, exact money, and recoverable history. + +## Decision + +Use a normalized PostgreSQL 18.6-or-later supported 18.x database. Search, graph, vector, and analytics stores are rebuildable projections. Use UUIDv7 and transactional outbox. + +## Consequences + +The canonical layer is robust and portable. Projection rebuild and database lifecycle require operational investment. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0010-rust-compute-boundary.md b/docs/adr/0010-rust-compute-boundary.md new file mode 100644 index 0000000..fbe9273 --- /dev/null +++ b/docs/adr/0010-rust-compute-boundary.md @@ -0,0 +1,21 @@ +# ADR-0010: Use Rust for production computation and prohibit heuristic scores + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +Commercial scoring, temporal measurement, vector/matrix work, and performance-critical paths require predictable safety and concurrency. Arbitrary weighted scores are not defensible. + +## Decision + +Implement ELUNVERA production logic and numerical kernels in Rust. Use TEPP or fast-mlsirm for research-backed measurement where applicable. Do not ship undocumented rule-of-thumb probabilities or health scores. + +## Consequences + +Performance and reproducibility improve. Scientific model development has a higher evidence burden, which is intentional. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0011-contract-versioning.md b/docs/adr/0011-contract-versioning.md new file mode 100644 index 0000000..193958e --- /dev/null +++ b/docs/adr/0011-contract-versioning.md @@ -0,0 +1,21 @@ +# ADR-0011: Version HTTP and events independently + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +Consumers need stable contracts across deployment and provider changes. HTTP resources and asynchronous facts evolve at different rates. + +## Decision + +OpenAPI 3.2.0 is the HTTP source, AsyncAPI 3.1.0 the event source, JSON Schema 2020-12 the payload source, CloudEvents 1.0 the envelope, and RFC 9457 the error format. Breaking changes create a new major version. + +## Consequences + +SDK generation and compatibility tests are possible. Contract review becomes a release gate. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0012-quality-release-gates.md b/docs/adr/0012-quality-release-gates.md new file mode 100644 index 0000000..f359aed --- /dev/null +++ b/docs/adr/0012-quality-release-gates.md @@ -0,0 +1,21 @@ +# ADR-0012: Require evidence-based release gates + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +A documentation-rich or test-heavy repository can still ship broken behavior if current-head, realistic, security, migration, and recovery evidence is missing. + +## Decision + +Require 100% ELUNVERA-owned production statement and branch coverage, 100% public API documentation, current-head checks, realistic PostgreSQL and E2E tests, supply-chain evidence, migration and restore rehearsal, and independent review. + +## Consequences + +Release confidence is evidence-backed. CI cost and review time increase and must be managed rather than bypassed. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0013-brand-and-license.md b/docs/adr/0013-brand-and-license.md new file mode 100644 index 0000000..f76fcf9 --- /dev/null +++ b/docs/adr/0013-brand-and-license.md @@ -0,0 +1,21 @@ +# ADR-0013: Preserve ELUNVERA brand and defer code license decision + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +The brand was selected through preliminary domain and clearance review, but formal trademark registration and software licensing are separate decisions. + +## Decision + +Use `ELUNVERA`/`Elunvera` and Korean `엘룬베라` consistently. Do not claim trademark registration. Do not accept distributable source code until the repository license is decided and documented. + +## Consequences + +Brand consistency is protected without making unsupported legal claims. Implementation is gated on a license decision. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0014-ux-design-system.md b/docs/adr/0014-ux-design-system.md new file mode 100644 index 0000000..28411db --- /dev/null +++ b/docs/adr/0014-ux-design-system.md @@ -0,0 +1,21 @@ +# ADR-0014: Use a three-band account UX and shared design system + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +CRM dashboards often fragment account truth into unrelated cards and expose implementation boundaries. Relationship graphs alone are inaccessible and hard to act on. + +## Decision + +Structure account overview into context, relationship structure, and action/risk bands. Create a Figma library, source-controlled design tokens, Storybook inventory, exact-value alternatives, Korean/English copy, and WCAG 2.2 AA evidence. + +## Consequences + +The interface follows the user’s decision flow. Design-system and accessibility work are mandatory before UI completion. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0015-retention-disposition.md b/docs/adr/0015-retention-disposition.md new file mode 100644 index 0000000..84d7d58 --- /dev/null +++ b/docs/adr/0015-retention-disposition.md @@ -0,0 +1,21 @@ +# ADR-0015: Make retention, legal hold, and disposition explicit workflows + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +CRM data cannot be kept indefinitely or deleted through ad hoc database operations. Historical and legal obligations differ by record class. + +## Decision + +Version retention policies, represent legal holds, execute bounded disposition jobs with dry-run and item receipts, and preserve minimal deletion proof. Destructive bulk actions require maker-checker approval. + +## Consequences + +Privacy and auditability improve. Storage and disposition orchestration become product responsibilities. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/0016-cwl-ecosystem-boundaries.md b/docs/adr/0016-cwl-ecosystem-boundaries.md new file mode 100644 index 0000000..d09bc2f --- /dev/null +++ b/docs/adr/0016-cwl-ecosystem-boundaries.md @@ -0,0 +1,21 @@ +# ADR-0016: Integrate CWL products without direct SQL or code copying + +- **Status:** Proposed +- **Date:** 2026-08-27 +- **Decision owners:** ELUNVERA maintainers + +## Context + +CWL components have distinct authoritative responsibilities and maturity. Copying code or reading another product database would create inconsistent truth and release coupling. + +## Decision + +Use released packages for small stateless libraries and versioned APIs/events for stateful products. Prohibit service-to-service direct SQL. Record each dependency’s maturity and fallback behavior. + +## Consequences + +The ecosystem remains modular and independently releasable. Integration availability and contract drift require explicit monitoring. + +## Compliance and verification + +The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. diff --git a/docs/adr/README.md b/docs/adr/README.md new file mode 100644 index 0000000..2858955 --- /dev/null +++ b/docs/adr/README.md @@ -0,0 +1,22 @@ +# ELUNVERA Architecture Decision Records + +Status values: `Proposed`, `Accepted`, `Superseded`, `Rejected`. + +| ADR | Decision | Status | +|---|---|---| +| [0001](./0001-product-boundary.md) | Own CRM truth; federate adjacent products | Proposed | +| [0002](./0002-modular-monolith.md) | Begin as a modular monolith | Proposed | +| [0003](./0003-keyverse-identity.md) | Use Keyverse as identity authority | Proposed | +| [0004](./0004-bitemporal-truth.md) | Represent relationship truth bitemporally | Proposed | +| [0005](./0005-first-class-relationships.md) | Make relationships first-class records | Proposed | +| [0006](./0006-provider-neutral-integrations.md) | Use capability-specific integration ports | Proposed | +| [0007](./0007-purpose-aware-privacy.md) | Use purpose-aware field selection instead of universal masking | Proposed | +| [0008](./0008-ai-human-judgment.md) | Separate model claims from authoritative facts | Proposed | +| [0009](./0009-postgresql-system-of-record.md) | Use PostgreSQL 18 as canonical system of record | Proposed | +| [0010](./0010-rust-compute-boundary.md) | Use Rust for production computation and prohibit heuristic scores | Proposed | +| [0011](./0011-contract-versioning.md) | Version HTTP and events independently | Proposed | +| [0012](./0012-quality-release-gates.md) | Require evidence-based release gates | Proposed | +| [0013](./0013-brand-and-license.md) | Preserve ELUNVERA brand and defer code license decision | Proposed | +| [0014](./0014-ux-design-system.md) | Use a three-band account UX and shared design system | Proposed | +| [0015](./0015-retention-disposition.md) | Make retention, legal hold, and disposition explicit workflows | Proposed | +| [0016](./0016-cwl-ecosystem-boundaries.md) | Integrate CWL products without direct SQL or code copying | Proposed | diff --git a/docs/doctoring/REFERENCES.md b/docs/doctoring/REFERENCES.md new file mode 100644 index 0000000..418b838 --- /dev/null +++ b/docs/doctoring/REFERENCES.md @@ -0,0 +1,59 @@ +# ELUNVERA Research and Standards References + +References use APA 7th style. URLs identify authoritative or canonical sources. Inclusion indicates design traceability, not certification. + +## CRM and relationship research + +Lemon, K. N., & Verhoef, P. C. (2016). Understanding customer experience throughout the customer journey. *Journal of Marketing, 80*(6), 69–96. https://doi.org/10.1509/jm.15.0420 + +Morgan, R. M., & Hunt, S. D. (1994). The commitment-trust theory of relationship marketing. *Journal of Marketing, 58*(3), 20–38. https://doi.org/10.1177/002224299405800302 + +Payne, A., & Frow, P. (2005). A strategic framework for customer relationship management. *Journal of Marketing, 69*(4), 167–176. https://doi.org/10.1509/jmkg.2005.69.4.167 + +Reinartz, W., Krafft, M., & Hoyer, W. D. (2004). The customer relationship management process: Its measurement and impact on performance. *Journal of Marketing Research, 41*(3), 293–305. https://doi.org/10.1509/jmkr.41.3.293.35991 + +## Customer satisfaction and complaints + +International Organization for Standardization. (2018). *Quality management—Customer satisfaction—Guidelines for complaints handling in organizations (ISO 10002:2018).* https://www.iso.org/standard/71580.html + +International Organization for Standardization. (2018). *Quality management—Customer satisfaction—Guidelines for monitoring and measuring (ISO 10004:2018).* https://www.iso.org/standard/71582.html + +## Security, privacy, and AI governance + +Autio, C., Schwartz, R., Dunietz, J., Jain, S., Stanley, M., Tabassi, E., Hall, P., & Roberts, K. (2024). *Artificial intelligence risk management framework: Generative artificial intelligence profile (NIST AI 600-1).* National Institute of Standards and Technology. https://doi.org/10.6028/NIST.AI.600-1 + +International Organization for Standardization & International Electrotechnical Commission. (2022). *Information security, cybersecurity and privacy protection—Information security management systems—Requirements (ISO/IEC 27001:2022).* https://www.iso.org/standard/27001 + +International Organization for Standardization & International Electrotechnical Commission. (2023). *Information technology—Artificial intelligence—Management system (ISO/IEC 42001:2023).* https://www.iso.org/standard/81230.html + +International Organization for Standardization & International Electrotechnical Commission. (2025). *Information security, cybersecurity and privacy protection—Privacy information management systems—Requirements and guidance (ISO/IEC 27701:2025).* https://www.iso.org/standard/27701 + +National Institute of Standards and Technology. (2020). *NIST privacy framework: A tool for improving privacy through enterprise risk management, version 1.0.* https://www.nist.gov/privacy-framework + +Tabassi, E. (2023). *Artificial intelligence risk management framework (AI RMF 1.0) (NIST AI 100-1).* National Institute of Standards and Technology. https://doi.org/10.6028/NIST.AI.100-1 + +OWASP Foundation. (2023). *OWASP API security top 10—2023.* https://owasp.org/API-Security/editions/2023/en/0x11-t10/ + +OWASP Foundation. (2025). *OWASP top 10:2025.* https://owasp.org/Top10/2025/ + +## Software and data contracts + +Cloud Native Computing Foundation. (2022). *CloudEvents specification version 1.0.2.* https://github.com/cloudevents/spec/releases/tag/ce@v1.0.2 + +OpenAPI Initiative. (2025). *OpenAPI specification version 3.2.0.* https://spec.openapis.org/oas/v3.2.0.html + +AsyncAPI Initiative. (2026). *AsyncAPI specification version 3.1.0.* https://www.asyncapi.com/docs/reference/specification/v3.1.0 + +PostgreSQL Global Development Group. (2026). *PostgreSQL 18.6 documentation.* https://www.postgresql.org/docs/18/ + +World Wide Web Consortium. (2024). *Web content accessibility guidelines (WCAG) 2.2.* https://www.w3.org/TR/WCAG22/ + +## Law and regulation references + +European Parliament & Council of the European Union. (2016). *Regulation (EU) 2016/679 (General Data Protection Regulation).* https://eur-lex.europa.eu/eli/reg/2016/679/oj + +Republic of Korea. (2025). *Personal Information Protection Act, Act No. 20897, effective October 2, 2025.* Korean Law Information Center. https://www.law.go.kr/ + +Republic of Korea. (2026). *Enforcement Decree of the Personal Information Protection Act, effective August 20, 2026.* Korean Law Information Center. https://www.law.go.kr/ + +The Act amendment scheduled to take effect on September 11, 2026 is tracked as forthcoming and is not treated as effective on the document date. diff --git a/docs/doctoring/RESEARCH_BASIS.md b/docs/doctoring/RESEARCH_BASIS.md new file mode 100644 index 0000000..d56ffd9 --- /dev/null +++ b/docs/doctoring/RESEARCH_BASIS.md @@ -0,0 +1,29 @@ +# ELUNVERA Research Basis + +## Strategic CRM + +Payne and Frow frame CRM as a cross-functional strategic process rather than a database or sales-automation module. ELUNVERA therefore separates account strategy, value and outcomes, multichannel interaction integration, information management, and performance assessment while preserving one coherent relationship record. + +## Relationship quality + +Morgan and Hunt identify commitment and trust as central mediating constructs in relationship marketing. ELUNVERA represents commitments as explicit time-valid records and does not collapse trust into an undocumented “health” score. Any future measurement of trust or commitment requires an instrument, model, uncertainty, validation, and governance. + +## Customer journey + +Lemon and Verhoef show that customer experience spans touchpoints and phases across the journey. ELUNVERA links interactions, outcomes, complaints, stakeholders, and opportunity facts without claiming ownership of every channel. + +## CRM performance + +Reinartz, Krafft, and Hoyer examine CRM as a process with measurable performance implications. ELUNVERA therefore measures workflow completeness and customer outcomes separately from adoption vanity metrics and does not infer causal commercial impact from usage alone. + +## Complaints and satisfaction + +ISO 10002 and ISO 10004 support structured complaint handling and customer-satisfaction monitoring. The product separates complaint lifecycle, remedy, outcome, and satisfaction observation; it does not treat one survey number as the complete relationship state. + +## Measurement discipline + +A customer or stakeholder score is a measurement claim. ELUNVERA requires defined constructs and outcomes, valid sampling or denominator, temporal and multilevel structure, calibration, uncertainty, fairness evaluation, and reproducible model artifacts. TEPP and fast-mlsirm are preferred CWL components where their validated scope fits. + +## Limits + +The cited literature supports product structure and evaluation questions; it does not prove that ELUNVERA as currently documented improves revenue, retention, trust, or satisfaction. Those claims require implemented software and empirical customer evidence. diff --git a/docs/doctoring/STANDARD_TRACEABILITY.md b/docs/doctoring/STANDARD_TRACEABILITY.md new file mode 100644 index 0000000..7e74989 --- /dev/null +++ b/docs/doctoring/STANDARD_TRACEABILITY.md @@ -0,0 +1,22 @@ +# ELUNVERA Standard Traceability + +| External source | Product decision | Contract or document | Required evidence | Current status | +|---|---|---|---|---| +| ISO 10002:2018 | complaint intake, acknowledgement, investigation, remedy, follow-up | PRD, DATA_MODEL, complaint API | complaint E2E and audit receipt | Designed only | +| ISO 10004:2018 | versioned satisfaction observations and monitoring context | PRD, DATA_MODEL | instrument/model trace and reporting tests | Designed only | +| ISO/IEC 27001:2022 + Amd 1:2024 | security management concerns and evidence | SECURITY, THREAT_MODEL | implemented controls and independent audit | Designed only | +| ISO/IEC 27701:2025 | purpose, rights, retention, controller/processor context | PRIVACY, DATA_MODEL | privacy workflow and governance evidence | Designed only | +| NIST Privacy Framework 1.0 | privacy risk and lifecycle outcomes | PRIVACY, SECURITY | profile and control evidence | Designed only | +| ISO/IEC 42001:2023 | model inventory, approval, oversight, incident and monitoring | TRD, SECURITY, ADR-0008 | model lifecycle and review evidence | Designed only | +| NIST AI RMF 1.0 / NIST AI 600-1 | Govern, Map, Measure, Manage for AI claims | TEST_STRATEGY, THREAT_MODEL | TEVV, incident, prompt-injection evidence | Designed only | +| OWASP Top 10:2025 | web application risk baseline | SECURITY, TEST_STRATEGY | SAST, DAST, code review and tests | Designed only | +| OWASP API Security Top 10:2023 | object/property/function authorization and resource bounds | API_CONTRACT, SECURITY | API adversarial tests | Designed only | +| OpenAPI 3.2.0 | authoritative HTTP description | schemas/openapi.yaml | schema and SDK validation | Draft schema | +| AsyncAPI 3.1.0 | authoritative event description | schemas/asyncapi.yaml | schema and consumer tests | Draft schema | +| CloudEvents 1.0.2 | event envelope and replay identity | API_CONTRACT, schemas | duplicate/reorder tests | Draft schema | +| PostgreSQL 18.6 | UUIDv7, temporal and relational baseline | TRD, DATA_MODEL | real DB migration and restore | Not implemented | +| WCAG 2.2 | accessible CRM interface | UX_SPEC, Storybook inventory | automated and assistive-tech audit | Not implemented | +| Korean PIPA | lawful, purpose-limited personal-data processing | PRIVACY, SECURITY | jurisdiction-specific legal and operational review | Design reference | +| GDPR | rights, purpose, accountability where applicable | PRIVACY | territorial-scope and DPA review | Design reference | + +“Designed only” means no compliance or certification claim may be made. diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md new file mode 100644 index 0000000..e78fede --- /dev/null +++ b/docs/product-technical-gap-baseline.md @@ -0,0 +1,142 @@ +# ELUNVERA Product–Technical Gap Baseline + +- **Baseline version:** 0.1 +- **Observed date:** 2026-08-27 +- **Repository:** `ContextualWisdomLab/ELUNVERA` +- **Target integration branch:** `develop` +- **Evidence scope:** repository metadata plus this documentation change + +## 1. Executive status + +ELUNVERA is a newly created public repository. Before this baseline, it contained no branches, commits, runtime, database migrations, user interface, release, checks, or production evidence. This change establishes product and technical design contracts only. + +**Current honest classification:** `design baseline / pre-implementation`. + +The repository must not be described as alpha, beta, production-ready, secure, compliant, scalable, accessible, or commercially validated until the corresponding implementation and evidence exist. + +## 2. Product definition established by this baseline + +ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence system of record. It owns tenant-scoped commercial account, party, relationship, interaction metadata, commitment, opportunity, customer outcome, complaint, satisfaction observation, privacy workflow, audit, and provenance facts. + +It deliberately does not own identity, email/calendar/file hosting, generalized project execution, billing, ontology/catalog, or LLM routing. Those capabilities are consumed from CWL products through versioned contracts. + +## 3. Traceability matrix + +| Product concern | Product requirement | Technical decision | Contract/data | Current implementation | Required next evidence | +|---|---|---|---|---|---| +| Account continuity | PRD FR-001–006 | modular account registry | `commercial_account`, account APIs | none | Rust API, migration, E2E | +| Stakeholder history | FR-010–015 | first-class bitemporal relationship | relationship tables/events | none | temporal/property/DB tests | +| Interaction context | FR-020–024 | metadata projection, source refs | interaction/commitment APIs | none | naruon/ThreadWeave contract tests | +| Opportunity truth | FR-030–036 | versioned process and immutable snapshots | opportunity tables/events | none | stage and exact-money tests | +| Complaints/outcomes | FR-040–044 | structured complaint/outcome modules | complaint/outcome APIs | none | ISO-aligned E2E evidence | +| Search/intelligence | FR-050–054 | rebuildable projection and model claims | search/model jobs | none | retrieval and unsupported-claim tests | +| Privacy/rights | FR-060–064 | purpose-aware field selection | rights/retention models | none | PIPA/GDPR profile review and E2E | +| Tenant isolation | NFR security | Keyverse + RLS | auth context | none | adversarial cross-tenant suite | +| Availability | NFR reliability | operability and restore contracts | health/SLO/runbook | none | live telemetry and restore rehearsal | +| Accessibility | NFR UX | WCAG 2.2 AA + Storybook | UX and design system | none | Figma, UI, AT audit | +| Scientific scoring | P-05 | Rust + TEPP/fast-mlsirm, no heuristics | model artifact/claim | none | validation study and model release gate | + +## 4. Gap register + +### G-001 Repository governance + +**Gap:** no committed `develop` branch, ruleset, CODEOWNERS, required checks, labels, or release policy. +**Risk:** changes can bypass current-head review and the requested PR flow. +**Action:** establish bootstrap commit, `develop`, branch ruleset, independent approval, unresolved-thread protection, required checks, update-branch, squash merge, and branch deletion policy. +**Exit evidence:** ruleset API snapshot and tested PR. + +### G-002 Executable Rust foundation + +**Gap:** no Cargo workspace or production code. +**Risk:** architecture and quality goals are unverified. +**Action:** implement the M1 Rust workspace through TDD, beginning with identity/tenant context and account/party/relationship kernel. +**Exit evidence:** build, lint, unit/property/integration, coverage, and doc reports. + +### G-003 PostgreSQL lifecycle + +**Gap:** no migration, RLS, temporal constraint, pool, backup, or restore. +**Risk:** canonical truth and isolation are conceptual only. +**Action:** pin supported PostgreSQL 18.x, create 3NF migrations, RLS, temporal constraints, outbox, clean/upgrade rehearsal, encrypted backup, and restore validation. +**Exit evidence:** PostgreSQL integration and restore artifacts. + +### G-004 Keyverse integration + +**Gap:** no OIDC/JWKS/SCIM implementation. +**Risk:** no authenticated remote operation is safe. +**Action:** implement exact issuer/audience/token validation and immutable authorization context; separate CRM party identity from authentication subject. +**Exit evidence:** negative token and tenant tests. + +### G-005 Account and relationship UX + +**Gap:** no Figma file, design tokens, Storybook, UI, screenshots, or accessibility evidence. +**Risk:** product remains a database design rather than a usable CRM. +**Action:** create the three-band account experience in Figma, record file ID in ADR, implement shared tokens and Storybook edge states, then E2E and AT audit. +**Exit evidence:** reviewed Figma, screenshots, interaction tests, WCAG report. + +### G-006 Provider and CWL contracts + +**Gap:** adapters and consumer contracts do not exist. +**Risk:** integrations may duplicate authority or leak PII. +**Action:** implement one bounded vertical at a time, starting with Keyverse and then customer-controlled interaction metadata; publish provider/consumer fixtures in both repositories. +**Exit evidence:** conformance, duplicate/reorder, outage, and reconciliation tests. + +### G-007 Privacy operation + +**Gap:** purpose, rights, retention, hold, export, and disposition are documentation only. +**Risk:** product cannot responsibly process production customer data. +**Action:** implement policy decision receipts and complete rights/disposition workflows before production PII. +**Exit evidence:** jurisdiction-reviewed policies and realistic rights tests. + +### G-008 Security and supply chain + +**Gap:** no CI, SAST, secret scan, dependency review, SBOM, provenance, signatures, or penetration test. +**Risk:** no trustworthy artifact exists. +**Action:** use central `.github` reusable workflows, exact pins, minimal permissions, and signed release pipeline. +**Exit evidence:** current-head checks and signed release candidate. + +### G-009 Operability + +**Gap:** no health endpoints, telemetry, SLO, alert, capacity, incident, or recovery runtime. +**Risk:** failures and data loss cannot be detected or managed. +**Action:** implement liveness/startup/readiness, OTLP, low-cardinality metrics, queue/backpressure, capacity benchmark, runbooks, and rehearsal. +**Exit evidence:** SLO dashboard and operational drill receipts. + +### G-010 Model governance and measurement + +**Gap:** no model, dataset, benchmark, validity, fairness, or calibration evidence. +**Risk:** “relationship intelligence” could become ungrounded profiling. +**Action:** release no score until a specific outcome and population are defined; validate through contextual-orchestrator plus TEPP/fast-mlsirm where appropriate; preserve evidence, uncertainty, review, and appeal. +**Exit evidence:** model card, evaluation report, recovery/calibration metrics, monitoring. + +### G-011 Commercial and legal readiness + +**Gap:** no software license, trademark registration, terms, DPA, support policy, pricing, entitlement, or billing integration. +**Risk:** a public design repository is not a sellable product. +**Action:** decide license, complete trademark/legal review, define deployment/support and Billing Control Plane integration after core product evidence. +**Exit evidence:** approved legal/commercial package. + +### G-012 Product validation + +**Gap:** no customer interviews, usability data, activation, retention, willingness-to-pay, or outcome study. +**Risk:** engineering completeness may not create buyer value. +**Action:** validate the account-preparation, opportunity-review, and complaint-recovery verticals with target users and measure time-to-context, evidence coverage, correction rate, and workflow outcome. +**Exit evidence:** research protocol and anonymized findings. + +## 5. Highest-leverage implementation order + +```text +repository governance +→ identity and tenant boundary +→ PostgreSQL account/party/relationship kernel +→ audit, outbox, idempotency, temporal APIs +→ three-band account UX +→ opportunity and commitment vertical +→ complaints, outcomes, and privacy workflows +→ bounded CWL integrations +→ validated relationship intelligence +→ scale, security, accessibility, recovery, and commercial GA +``` + +## 6. Release truth + +The documentation baseline closes the absence of a coherent product definition and implementation contract. It closes none of the runtime, security, privacy, accessibility, model-validity, scalability, operational, legal, or market-validation gaps listed above. diff --git a/docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md b/docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md new file mode 100644 index 0000000..3563111 --- /dev/null +++ b/docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md @@ -0,0 +1,433 @@ +# ELUNVERA Foundation Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Deliver the first executable ELUNVERA vertical: authenticated tenant-isolated accounts, parties, time-valid relationships, evidence references, immutable audit, and a three-band account read model. + +**Architecture:** A Rust modular monolith exposes OpenAPI-derived HTTP contracts over a PostgreSQL 18 canonical store. Writes use idempotency, optimistic concurrency, RLS, temporal constraints, and a transactional outbox; a worker builds a read model consumed by a Next.js interface. + +**Tech Stack:** Rust stable, Axum, Tokio, SQLx, PostgreSQL 18.6+, OpenAPI 3.2.0, JSON Schema 2020-12, Next.js/React/TypeScript, OpenTelemetry, cargo-nextest, cargo-llvm-cov, proptest, cargo-fuzz, Playwright, Storybook. + +**Spec:** `docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md` + +## Global Constraints + +- The integration base is `develop`. +- Canonical database objects use at least two-word `snake_case` names. +- Production logic and arithmetic are Rust; TypeScript is UI/client only. +- PostgreSQL is canonical; search and graph are projections. +- Keyverse is identity authority; no local passwords. +- Every tenant-owned access is database and application isolated. +- Relationship facts are first-class and bitemporal. +- External identifiers never become internal primary keys. +- Money uses exact decimal representations. +- No heuristic relationship-health or forecast scores. +- ELUNVERA-owned production statement, branch, and public API documentation coverage are each 100%. +- Every task updates relevant docs, CHANGELOG, and the gap baseline. + +--- + +### Task 1: Establish the Rust workspace and exact quality gate + +**Files:** +- Create: `Cargo.toml` +- Create: `rust-toolchain.toml` +- Create: `crates/domain_contracts/Cargo.toml` +- Create: `crates/domain_contracts/src/lib.rs` +- Create: `tests/contract/repository_layout_test.py` +- Create: `.github/workflows/product.yml` +- Modify: `CHANGELOG.md` + +**Interfaces:** +- Produces: workspace crate `domain_contracts`; command `cargo test --workspace`; exact quality workflow. + +- [ ] **Step 1: Write the failing repository contract test** + +```python +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] + + +def test_foundation_workspace_contract() -> None: + required = [ + ROOT / "Cargo.toml", + ROOT / "rust-toolchain.toml", + ROOT / "crates/domain_contracts/src/lib.rs", + ROOT / ".github/workflows/product.yml", + ] + assert all(path.is_file() for path in required) +``` + +- [ ] **Step 2: Verify the test fails** + +Run: `python -m pytest tests/contract/repository_layout_test.py -q` +Expected: failure because the workspace files do not exist. + +- [ ] **Step 3: Create the minimal warning-free workspace** + +```rust +//! Versioned domain contracts shared by ELUNVERA foundation modules. + +#![forbid(unsafe_code)] +#![deny(missing_docs)] + +/// Contract version implemented by this crate. +pub const CONTRACT_VERSION: &str = "0.1.0"; +``` + +Pin the stable compiler in `rust-toolchain.toml`, deny warnings in CI, and configure format, Clippy, test, doc, and coverage commands. + +- [ ] **Step 4: Run the foundation gate** + +Run: + +```bash +python -m pytest tests/contract/repository_layout_test.py -q +cargo fmt --all -- --check +cargo clippy --workspace --all-targets --all-features -- -D warnings +cargo test --workspace --all-features +cargo doc --workspace --no-deps +``` + +Expected: all pass without warnings. + +- [ ] **Step 5: Commit** + +```bash +git add Cargo.toml rust-toolchain.toml crates tests .github CHANGELOG.md +git commit -m "build: establish Rust foundation quality gate" +``` + +### Task 2: Implement verified authorization context + +**Files:** +- Create: `crates/authorization_context/Cargo.toml` +- Create: `crates/authorization_context/src/lib.rs` +- Create: `crates/authorization_context/tests/authorization_context.rs` +- Modify: `Cargo.toml` +- Modify: `docs/SECURITY.md` + +**Interfaces:** +- Produces: `VerifiedRequestContext`, `TenantReference`, `PurposeCode`, `AuthorizationError`. + +- [ ] **Step 1: Write failing context tests** + +```rust +#[test] +fn caller_supplied_tenant_cannot_override_verified_tenant() { + let context = verified_context("tenant_alpha"); + assert_ne!(context.tenant_reference().as_str(), "tenant_beta"); +} + +#[test] +fn missing_purpose_is_rejected() { + let result = VerifiedRequestContext::try_new(valid_claims_without_purpose()); + assert!(matches!(result, Err(AuthorizationError::MissingPurpose))); +} +``` + +- [ ] **Step 2: Verify RED** + +Run: `cargo test -p authorization_context` +Expected: compilation failure because the types do not exist. + +- [ ] **Step 3: Implement immutable typed context** + +Use private fields, validated constructors, opaque tenant/workspace references, bounded role/scope sets, UTC time checks, and no deserialization path that accepts authority directly from HTTP headers. + +- [ ] **Step 4: Verify GREEN and coverage** + +Run: + +```bash +cargo test -p authorization_context +cargo llvm-cov -p authorization_context --branch --fail-under-lines 100 --fail-under-functions 100 --fail-under-regions 100 +``` + +Expected: all tests pass and production coverage is complete. + +- [ ] **Step 5: Commit** + +```bash +git add crates/authorization_context Cargo.toml docs/SECURITY.md +git commit -m "feat: add verified tenant authorization context" +``` + +### Task 3: Create PostgreSQL lifecycle, RLS, and temporal schema + +**Files:** +- Create: `database/migrations/0001_foundation.sql` +- Create: `database/migrations/0001_foundation.down.sql` +- Create: `tests/integration/foundation_schema.rs` +- Create: `infrastructure/compose.yaml` +- Create: `scripts/rehearse-migrations.sh` +- Modify: `docs/DATA_MODEL.md` + +**Interfaces:** +- Produces: `tenant_account`, `workspace_record`, `workspace_member`, `party_record`, `commercial_account`, `relationship_record`, `relationship_participant`, `source_receipt`, `evidence_reference`, `audit_event`, `outbox_event`. + +- [ ] **Step 1: Write failing migration integration tests** + +Test clean migration, database object naming, RLS denial without tenant context, cross-tenant denial, temporal overlap rejection, UUIDv7 defaults, and down/up rehearsal. + +- [ ] **Step 2: Start isolated PostgreSQL and verify RED** + +Run: + +```bash +podman compose -f infrastructure/compose.yaml -p elunvera-foundation-test up -d postgres +cargo test --test foundation_schema -- --nocapture +``` + +Expected: failure because migrations do not exist. + +- [ ] **Step 3: Implement normalized migration** + +Use tenant foreign keys, `tstzrange` valid/recorded intervals, temporal/exclusion constraints, RLS policies using transaction-local verified tenant settings, exact audit and outbox fields, and no business-critical JSONB. + +- [ ] **Step 4: Rehearse and verify GREEN** + +Run: + +```bash +./scripts/rehearse-migrations.sh +cargo test --test foundation_schema -- --nocapture +``` + +Expected: clean install, down/up rehearsal, tenant attacks, and temporal constraints pass. + +- [ ] **Step 5: Remove isolated runtime and commit** + +```bash +podman compose -f infrastructure/compose.yaml -p elunvera-foundation-test down -v +git add database tests/integration infrastructure scripts docs/DATA_MODEL.md +git commit -m "feat: add tenant-isolated temporal CRM schema" +``` + +### Task 4: Implement account, party, and relationship domain modules + +**Files:** +- Create: `crates/account_registry/src/lib.rs` +- Create: `crates/party_registry/src/lib.rs` +- Create: `crates/relationship_registry/src/lib.rs` +- Create: `crates/*/tests/*.rs` +- Modify: `Cargo.toml` + +**Interfaces:** +- Produces: `CreateAccountCommand`, `CreatePartyCommand`, `RecordRelationshipCommand`, `AccountRepository`, `PartyRepository`, `RelationshipRepository`, domain events from `domain_contracts`. +- Consumes: `VerifiedRequestContext` and schema from Tasks 2–3. + +- [ ] **Step 1: Write failing state and property tests** + +Cover account creation, local party identity, n-ary relationship participants, evidence-or-manual-assertion requirement, time intervals, exclusive-role overlap, truth status, cross-tenant rejection, and correction without history deletion. + +- [ ] **Step 2: Verify RED** + +Run: `cargo test -p account_registry -p party_registry -p relationship_registry`. + +- [ ] **Step 3: Implement minimal domain behavior** + +Keep aggregate invariants in pure Rust types, persistence behind traits, errors exhaustive, and public APIs fully documented. Do not introduce a graph database dependency. + +- [ ] **Step 4: Verify property and mutation boundaries** + +Run: + +```bash +cargo test -p account_registry -p party_registry -p relationship_registry +cargo llvm-cov --workspace --branch --fail-under-lines 100 +``` + +Expected: all state transitions, negative branches, and production lines pass. + +- [ ] **Step 5: Commit** + +```bash +git add crates Cargo.toml +git commit -m "feat: implement account and relationship kernel" +``` + +### Task 5: Implement idempotent HTTP commands and operation receipts + +**Files:** +- Create: `apps/elunvera_api/Cargo.toml` +- Create: `apps/elunvera_api/src/main.rs` +- Create: `apps/elunvera_api/src/routes/accounts.rs` +- Create: `apps/elunvera_api/src/routes/relationships.rs` +- Create: `apps/elunvera_api/tests/http_contract.rs` +- Modify: `schemas/openapi.yaml` + +**Interfaces:** +- Produces: `/v1/accounts`, `/v1/parties`, `/v1/relationships`; RFC 9457 errors; ETag; operation receipt. +- Consumes: domain commands and verified context. + +- [ ] **Step 1: Write failing HTTP contract tests** + +Test missing/invalid identity, missing idempotency key, same-key same-payload replay, same-key different-payload conflict, stale `If-Match`, cross-tenant not-found, payload limit, and safe error copy. + +- [ ] **Step 2: Verify RED** + +Run: `cargo test -p elunvera_api --test http_contract`. + +- [ ] **Step 3: Implement minimal Axum routes** + +Validate OpenAPI schemas, construct authority only from middleware, commit aggregate and outbox in one transaction, return receipt and ETag, and map errors to stable Problem Details. + +- [ ] **Step 4: Validate contract and tests** + +```bash +cargo test -p elunvera_api +python scripts/validate-contracts.py +``` + +Expected: HTTP behavior and OpenAPI operation IDs are consistent. + +- [ ] **Step 5: Commit** + +```bash +git add apps schemas scripts +git commit -m "feat: expose idempotent CRM foundation API" +``` + +### Task 6: Implement outbox worker and account read projection + +**Files:** +- Create: `apps/elunvera_worker/Cargo.toml` +- Create: `apps/elunvera_worker/src/main.rs` +- Create: `crates/integration_outbox/src/lib.rs` +- Create: `crates/account_projection/src/lib.rs` +- Create: `tests/integration/outbox_projection.rs` +- Modify: `schemas/asyncapi.yaml` + +**Interfaces:** +- Produces: account/relationship CloudEvents and `AccountOverviewProjection`. +- Consumes: transactional outbox records. + +- [ ] **Step 1: Write failing duplicate, reorder, and crash tests** + +Prove one projection effect after duplicate delivery, recovery after worker termination between claim and completion, dead-letter isolation, and no authority flowing from projection to canonical tables. + +- [ ] **Step 2: Verify RED** + +Run: `cargo test --test outbox_projection -- --nocapture`. + +- [ ] **Step 3: Implement leasing, publishing, inbox receipt, and projection** + +Use bounded batches, heartbeat, retry classification, low-cardinality metrics, schema validation, and atomic projection receipt. + +- [ ] **Step 4: Verify GREEN** + +Run the test with repeated randomized delivery sequences and confirm the same final projection hash. + +- [ ] **Step 5: Commit** + +```bash +git add apps/elunvera_worker crates/integration_outbox crates/account_projection tests schemas/asyncapi.yaml +git commit -m "feat: project account context from durable events" +``` + +### Task 7: Build the accessible three-band account interface + +**Files:** +- Create: `apps/elunvera_web/` +- Create: `packages/design_tokens/` +- Create: `apps/elunvera_web/stories/` +- Create: `apps/elunvera_web/e2e/account-overview.spec.ts` +- Modify: `docs/UX_SPEC.md` +- Modify: `docs/adr/0014-ux-design-system.md` + +**Interfaces:** +- Produces: `AccountOverviewPage`, three band components, relationship table/graph toggle, evidence drawer, responsive and print views. +- Consumes: generated TypeScript client and `AccountOverviewProjection`. + +- [ ] **Step 1: Create and record the Figma library** + +Create reviewed desktop, tablet, mobile, Korean, English, print, loading, empty, stale, conflict, denied, and provider-unavailable frames. Record the real Figma File ID in ADR-0014; do not use a placeholder. + +- [ ] **Step 2: Write failing Storybook and Playwright interactions** + +Test keyboard band navigation, evidence drawer focus, graph-to-table parity, Korean/English rendering, stale state, safe next-action copy, and print exact values. + +- [ ] **Step 3: Verify RED** + +Run: + +```bash +pnpm --dir apps/elunvera_web test +pnpm --dir apps/elunvera_web test-storybook +pnpm --dir apps/elunvera_web playwright test +``` + +Expected: failures because components do not exist. + +- [ ] **Step 4: Implement from shared tokens** + +Use accessible semantic HTML, progressive enhancement, bounded graph rendering, no internal service names, and no color-only states. + +- [ ] **Step 5: Validate screenshots and accessibility, then commit** + +```bash +pnpm --dir apps/elunvera_web lint +pnpm --dir apps/elunvera_web typecheck +pnpm --dir apps/elunvera_web test --coverage +pnpm --dir apps/elunvera_web test-storybook +pnpm --dir apps/elunvera_web playwright test + +git add apps/elunvera_web packages/design_tokens docs +git commit -m "feat: add accessible three-band account workspace" +``` + +### Task 8: Complete operability, security, restoration, and release evidence + +**Files:** +- Create: `crates/telemetry/` +- Create: `apps/elunvera_api/src/health.rs` +- Create: `infrastructure/otel/` +- Create: `scripts/rehearse-restore.sh` +- Create: `docs/runbooks/foundation-incident.md` +- Create: `docs/validation/foundation-release-evidence.md` +- Modify: `docs/OPERABILITY.md` +- Modify: `docs/product-technical-gap-baseline.md` +- Modify: `CHANGELOG.md` + +**Interfaces:** +- Produces: `/healthz`, `/startupz`, `/readyz`, OTLP signals, restore receipt, release evidence manifest. + +- [ ] **Step 1: Write failing health, telemetry privacy, and restore tests** + +Prove liveness does not depend on DB, readiness fails without safe write/key/queue path, traces contain no fixture PII, and a restored environment preserves tenant/RLS/outbox/projection integrity. + +- [ ] **Step 2: Verify RED** + +Run the focused tests and restoration script; expect missing implementation failures. + +- [ ] **Step 3: Implement minimal operational path** + +Add low-cardinality metrics, correlation propagation, bounded status output, graceful drain, encrypted backup integration, and isolated restoration verification. + +- [ ] **Step 4: Run complete current-head evidence suite** + +```bash +cargo fmt --all -- --check +cargo clippy --workspace --all-targets --all-features -- -D warnings +cargo nextest run --workspace --all-features +cargo llvm-cov --workspace --branch --fail-under-lines 100 +python scripts/validate-contracts.py +./scripts/rehearse-migrations.sh +./scripts/rehearse-restore.sh +pnpm --dir apps/elunvera_web verify +``` + +Expected: every required check passes on the same exact head with no skipped release lane. + +- [ ] **Step 5: Update evidence and commit** + +```bash +git add crates/telemetry apps infrastructure scripts docs CHANGELOG.md +git commit -m "ops: complete ELUNVERA foundation readiness evidence" +``` + +## Plan completion gate + +The foundation is complete only when a target user can authenticate, create an account and parties, record and correct an evidence-linked time-valid relationship, view the accessible three-band account page, inspect the audit and operation receipt, and recover the same result from a tested backup without crossing tenant boundaries. diff --git a/docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md b/docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md new file mode 100644 index 0000000..81db2dd --- /dev/null +++ b/docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md @@ -0,0 +1,67 @@ +# ELUNVERA Product and Technical Baseline Design + +- **Date:** 2026-08-27 +- **Status:** Proposed +- **Scope:** Documentation and executable-contract design; no runtime implementation + +## 1. Intent + +Establish a coherent design baseline for a new evidence-centered B2B CRM that can enter implementation through `develop` without absorbing adjacent CWL products or inventing unvalidated commercial scores. + +## 2. Considered approaches + +### Full-suite CRM monolith + +Own identity, email, calendar, projects, billing, content, and intelligence in one repository. This offers a superficially simple sales story but duplicates CWL authorities and creates a large regulatory and operational blast radius. Rejected. + +### Graph-only relationship overlay + +Project existing customer systems into a graph and provide search/AI. This avoids another transactional store but cannot own stage history, commitments, complaint workflow, privacy rights, or accountable corrections. Rejected as the core product. + +### Federated CRM system of record with evidence-centered intelligence + +Own the customer relationship and commercial facts that require transactional authority. Consume adjacent capabilities through bounded contracts. Preserve first-class bitemporal relationships and separate model claims from facts. **Selected.** + +## 3. Product boundary + +ELUNVERA owns account, party, relationship, interaction metadata, commitment, opportunity, outcome, complaint, satisfaction observation, purpose, preference, rights workflow, audit, and provenance facts. Keyverse, naruon, ThreadWeave, LineageWeave, RankWeave, contextual-orchestrator, TEPP, fast-mlsirm, Semantic Data Portal, ScopeWeave, and Billing Control Plane retain their own authorities. + +## 4. Architecture + +The first implementation is a Rust modular monolith with PostgreSQL 18 as canonical store, transactional outbox, durable worker, rebuildable search/graph projections, and Next.js/TypeScript interfaces. Module contracts make later service extraction possible without requiring distributed transactions at inception. + +## 5. Data design + +- 3NF canonical records; +- UUIDv7 external identifiers; +- RLS or equivalent database tenant isolation; +- business-valid and system-recorded time; +- first-class n-ary relationship records; +- exact decimal money; +- external-provider IDs in mapping tables; +- immutable audit, stage, forecast, model, and disposition evidence; +- graph/search/vector as projections only. + +## 6. Command and event flow + +Mutations require verified identity context, purpose, idempotency key, and current aggregate version. Aggregate and outbox event commit atomically. Events use CloudEvents with versioned JSON Schema and at-least-once delivery; consumers deduplicate and record projection receipts. + +## 7. AI and measurement + +LLM work runs through contextual-orchestrator and produces model claims with evidence and uncertainty. A separate authorized command changes domain truth. Scores require construct and outcome definition, validation population, temporal and multilevel design, calibration, fairness, uncertainty, and release monitoring. Heuristic stage probabilities and weighted health scores are forbidden. + +## 8. UX + +The account overview follows three horizontal bands: account context, relationship structure, and action/risk. Graphs always have exact structured alternatives. Copy explains the customer’s next action and hides internal component names. Figma, design tokens, Storybook, Korean/English, responsive states, screenshots, and WCAG 2.2 AA evidence precede UI completion. + +## 9. Failure behavior + +Core CRM reads and writes do not depend on optional providers or LLMs. Integration failure produces an explicit stale/partial state and recovery action. Expensive operations are asynchronous, bounded, cancellable, and receipted. Restore, projection rebuild, duplicate/reorder, and provider-outage cases are first-class tests. + +## 10. Quality boundary + +ELUNVERA-owned shipped code requires 100% production statement and branch coverage and 100% public API documentation. Current-head checks, realistic PostgreSQL, security, accessibility, load, migration, recovery, SBOM, provenance, and independent review are release gates. + +## 11. Scope decision + +This specification is focused enough for one foundation implementation plan because the plan delivers a usable canonical account/relationship vertical. Later opportunity, complaint, integration, and intelligence milestones receive separate implementation plans. diff --git a/manifest.json b/manifest.json new file mode 100644 index 0000000..f18c217 --- /dev/null +++ b/manifest.json @@ -0,0 +1,334 @@ +{ + "schema_version": "1.0", + "product": "ELUNVERA", + "generated_at": "2026-08-27T00:00:00Z", + "algorithm": "SHA-256", + "self_excluded": true, + "file_count": 54, + "files": [ + { + "path": ".cwl/data-management.yaml", + "sha256": "28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671", + "size_bytes": 1727, + "line_count": 48 + }, + { + "path": ".github/pull_request_template.md", + "sha256": "d7584adf5eb9866449fc5f38dc490422bf23de31ae75e1bdb385265c68122d15", + "size_bytes": 1064, + "line_count": 38 + }, + { + "path": "AGENTS.md", + "sha256": "8d308fc7f687ad53e18aabc95cbb175a48450b8bfe502b29562f0afd9c950d13", + "size_bytes": 4022, + "line_count": 84 + }, + { + "path": "CHANGELOG.md", + "sha256": "335c872458d18069fd76569b0eb49ff1062c6f6b44ef2ba58e714e207ab1f098", + "size_bytes": 1154, + "line_count": 24 + }, + { + "path": "CLAUDE.md", + "sha256": "67f513ae368f851201f50b6f732f444a648b3a940ca261411edbbc4c9f1ab223", + "size_bytes": 1684, + "line_count": 34 + }, + { + "path": "CONTRIBUTING.md", + "sha256": "61698c99617bbdd3fab3150341899c967c647cf5aa5ec9756d9cf6fa99571e60", + "size_bytes": 1566, + "line_count": 43 + }, + { + "path": "README.md", + "sha256": "9d355be62b9bf5b8e90a6bfa204db40abbf5fd2d9307733501172983c465546c", + "size_bytes": 4974, + "line_count": 81 + }, + { + "path": "SECURITY.md", + "sha256": "4bfbb000844294b22ff9882211ee0a57b38e637002847cfdde8818b9276851eb", + "size_bytes": 1091, + "line_count": 32 + }, + { + "path": "docs/API_CONTRACT.md", + "sha256": "8c23a286938b7e44c5e6990104b249fe4dabb499f47f38566407cb324ddd7170", + "size_bytes": 9253, + "line_count": 287 + }, + { + "path": "docs/ARCHITECTURE.md", + "sha256": "f4e39936636d48ed0d4d1c21f02562860be1af19fe8eec2d75e1d9049c30861f", + "size_bytes": 9402, + "line_count": 250 + }, + { + "path": "docs/DATA_MODEL.md", + "sha256": "3bbfe050809c960406514ff3ad0d8a273dc84b80c377189fd23f2c80f40da10a", + "size_bytes": 15101, + "line_count": 504 + }, + { + "path": "docs/OPERABILITY.md", + "sha256": "1c725823885df063bb43d8d9e4d80258ed6b9ef5029bb97cdf5100f7ec7dc80d", + "size_bytes": 7003, + "line_count": 151 + }, + { + "path": "docs/PRD.md", + "sha256": "8d074776a4cd2a8465daefb98751cf01ffd7ffcb1a328f8deea6362e728ab860", + "size_bytes": 22102, + "line_count": 366 + }, + { + "path": "docs/PRIVACY.md", + "sha256": "0599406e743af7c561208da8ad505c704ea585cebeb941444d221584aad5e004", + "size_bytes": 6899, + "line_count": 141 + }, + { + "path": "docs/ROADMAP.md", + "sha256": "1a00a118088f908cce4449a1532f35231f383c7d415fff5136624bf970b926c7", + "size_bytes": 3418, + "line_count": 84 + }, + { + "path": "docs/SECURITY.md", + "sha256": "d10ae9757a7233b9ce73eaa038f75939d22da4709ac6db7ee16fe4b291bd64dd", + "size_bytes": 8100, + "line_count": 174 + }, + { + "path": "docs/STORYBOARD.md", + "sha256": "c9e2d38ca25e024a7599afeff711187be272cebc7c51a9ca603846bf33bda392", + "size_bytes": 2775, + "line_count": 41 + }, + { + "path": "docs/STORYBOOK_INVENTORY.md", + "sha256": "e210ed7072720bef3b825f226419ff25dd68ee412d5272f0e5d51234b8ea4fe1", + "size_bytes": 2354, + "line_count": 99 + }, + { + "path": "docs/TEST_STRATEGY.md", + "sha256": "b0f24b7fe2518c2d9e214868e7f7fe3189cc49307b988723dec5d939f82c9af0", + "size_bytes": 7302, + "line_count": 170 + }, + { + "path": "docs/THREAT_MODEL.md", + "sha256": "1dc10db1d5fb0a314e25cd78c9bb1ed90b40315dbb3a32d387c2b5758910100f", + "size_bytes": 7043, + "line_count": 132 + }, + { + "path": "docs/TRD.md", + "sha256": "13f332255239f79e773bcce00a6b19a2051ff5cb7273ae0e24ca6413a38ea0fc", + "size_bytes": 14747, + "line_count": 342 + }, + { + "path": "docs/UML.md", + "sha256": "882a33a38bda7494e370f4135b9a3d7c5d3cf054d47cc511f3813eb046916d0c", + "size_bytes": 3165, + "line_count": 115 + }, + { + "path": "docs/USER_STORIES.md", + "sha256": "cdc8e1a2b74d7821279dfe0f07dda2d25b9bae088a720b9a6fb19270af36208c", + "size_bytes": 3184, + "line_count": 37 + }, + { + "path": "docs/USE_CASES.md", + "sha256": "4df536423c1796793edd35c200b624e6ec1daa87adf6ace9748608f24c254022", + "size_bytes": 4357, + "line_count": 69 + }, + { + "path": "docs/UX_SPEC.md", + "sha256": "ed3dc4b9738f5a0fbfa2f8176379a14c4b3a222b7b305c1fc31ea61e257115be", + "size_bytes": 6609, + "line_count": 171 + }, + { + "path": "docs/VALIDATION_REPORT.md", + "sha256": "116e9549728e8b374ee492ad622ade97eec33e4bfc49d0b3e238109af1ef512c", + "size_bytes": 2008, + "line_count": 49 + }, + { + "path": "docs/WIREFRAMES.md", + "sha256": "e989815acd882701ff2737036ae6f278b5a01c45081204c3c65c33c9dc0e4f01", + "size_bytes": 4526, + "line_count": 81 + }, + { + "path": "docs/adr/0001-product-boundary.md", + "sha256": "86f3513bdfa2c2c8766c6c2afdbec7b099778982e9246efe729b5d9f76da3e24", + "size_bytes": 1151, + "line_count": 21 + }, + { + "path": "docs/adr/0002-modular-monolith.md", + "sha256": "0415bc80db206f5581c758a83f09abe14bfa5e45e76fbc2b38b7bb958d2342bb", + "size_bytes": 955, + "line_count": 21 + }, + { + "path": "docs/adr/0003-keyverse-identity.md", + "sha256": "10fccb512eff2665cf0b43ef5bbef1cdf4501962e0ae353777f131a75552c309", + "size_bytes": 865, + "line_count": 21 + }, + { + "path": "docs/adr/0004-bitemporal-truth.md", + "sha256": "d7d85c1fefeed397e417653a46e1ddd2d9505740f9369d2f16769dac344d373c", + "size_bytes": 875, + "line_count": 21 + }, + { + "path": "docs/adr/0005-first-class-relationships.md", + "sha256": "1130b14f9f448d3aba40086cb1355683c0d5b4891368706c860b41e5467a5852", + "size_bytes": 848, + "line_count": 21 + }, + { + "path": "docs/adr/0006-provider-neutral-integrations.md", + "sha256": "318a12fb63ed4c788af86aa45ff1c95430f6f199bf012c1f966b073be469e7a9", + "size_bytes": 861, + "line_count": 21 + }, + { + "path": "docs/adr/0007-purpose-aware-privacy.md", + "sha256": "9ce6767604ee5787e0e2b4f051272cb7a2288be4dc8ba06e1b7bd3ffe54b0664", + "size_bytes": 944, + "line_count": 21 + }, + { + "path": "docs/adr/0008-ai-human-judgment.md", + "sha256": "1d2d14e8b6b0a03a18180a6e1a7efe9b2212afda74bd250c1c8745e5f700706d", + "size_bytes": 950, + "line_count": 21 + }, + { + "path": "docs/adr/0009-postgresql-system-of-record.md", + "sha256": "9ca96bc56d1658c933f89e3fe34b24cf0707e1b2e4862bc4929c8f4889b36bf7", + "size_bytes": 862, + "line_count": 21 + }, + { + "path": "docs/adr/0010-rust-compute-boundary.md", + "sha256": "b9e7d8f0da93a8c5f8dec5892d097c2eaab7eb4057b1a0f7a510ff22f29a5ccf", + "size_bytes": 979, + "line_count": 21 + }, + { + "path": "docs/adr/0011-contract-versioning.md", + "sha256": "76381bc76cfd59fd2a4bbd8831c217f1e6ca2625079d5c59b90d09fadc5f8afb", + "size_bytes": 877, + "line_count": 21 + }, + { + "path": "docs/adr/0012-quality-release-gates.md", + "sha256": "7083f64c1d394ad57cb8a1f19a9728b39dc032f59c6c159dabf2603751625144", + "size_bytes": 945, + "line_count": 21 + }, + { + "path": "docs/adr/0013-brand-and-license.md", + "sha256": "9b54fd5c0fc4de13f647e1c8955c69c6cffd90766c8dd946e1d34322a7adc0de", + "size_bytes": 923, + "line_count": 21 + }, + { + "path": "docs/adr/0014-ux-design-system.md", + "sha256": "3121dfd4944a529a526a1ff3809d5c83a35360136973672f01a5d262f9a3d50a", + "size_bytes": 977, + "line_count": 21 + }, + { + "path": "docs/adr/0015-retention-disposition.md", + "sha256": "2b6b3fc4e3ddad2564e7bd9819d4aa4f980e3befb12d947ede25987a041e654c", + "size_bytes": 915, + "line_count": 21 + }, + { + "path": "docs/adr/0016-cwl-ecosystem-boundaries.md", + "sha256": "fb59ab82e8a9c5e19702412e25e22318587fd155a4dd41b14de6497b1de8066d", + "size_bytes": 964, + "line_count": 21 + }, + { + "path": "docs/adr/README.md", + "sha256": "b54b4bc29ff5a2d385c23bd7049bc64e1cf04277147afa70057b20ba8b5f46e1", + "size_bytes": 1806, + "line_count": 22 + }, + { + "path": "docs/doctoring/REFERENCES.md", + "sha256": "3508c3d2c9a886cb1e6fa5ed90a380e22feac730dcde737c953b1e1e04d3d5fb", + "size_bytes": 4519, + "line_count": 59 + }, + { + "path": "docs/doctoring/RESEARCH_BASIS.md", + "sha256": "1ecf6adb21fc6cfbf355fb61256c93fb20028ae228b8c910d97a867d73f184a4", + "size_bytes": 2221, + "line_count": 29 + }, + { + "path": "docs/doctoring/STANDARD_TRACEABILITY.md", + "sha256": "38d44ddfab32c0a7bf2bb7935bded795dd0a84800427e5518d64ff6a261f2314", + "size_bytes": 2560, + "line_count": 22 + }, + { + "path": "docs/product-technical-gap-baseline.md", + "sha256": "39e5adf829a46271ce3939cbf2259108b25d0ff39c26128c38229a2f808f8301", + "size_bytes": 8851, + "line_count": 142 + }, + { + "path": "docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md", + "sha256": "ed833198cc2e5f7ebcc9f22b402f25dbdc647ce19657c4759c85299f0c37f0fc", + "size_bytes": 16009, + "line_count": 433 + }, + { + "path": "docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md", + "sha256": "3ea901999f778ebe4aa5118024da82f4b72457814f8a715df7440ce41726cb5d", + "size_bytes": 4492, + "line_count": 67 + }, + { + "path": "schemas/asyncapi.yaml", + "sha256": "2670697f82e5046f07e9938bae12f95f59bba7c66113990a826820149b8b00a6", + "size_bytes": 2837, + "line_count": 75 + }, + { + "path": "schemas/events/opportunity-stage-changed-v1.schema.json", + "sha256": "1a65236b1a0703abbe74c568692c851336393c62e84e6977f13356a5a16f03b1", + "size_bytes": 1299, + "line_count": 57 + }, + { + "path": "schemas/events/relationship-changed-v1.schema.json", + "sha256": "5bd9b1504d8c1ad1c9c3df4cd1d8a39e31b4fc15a10633707da222be6814dcb0", + "size_bytes": 1358, + "line_count": 66 + }, + { + "path": "schemas/openapi.yaml", + "sha256": "03adaef269648275bd5d9e44d99a7f990f18efbf05a40771b628b971de79e8fb", + "size_bytes": 9293, + "line_count": 275 + } + ] +} diff --git a/schemas/asyncapi.yaml b/schemas/asyncapi.yaml new file mode 100644 index 0000000..8c1f7c3 --- /dev/null +++ b/schemas/asyncapi.yaml @@ -0,0 +1,75 @@ +asyncapi: 3.1.0 +info: + title: ELUNVERA Domain Events + version: 0.1.0 + description: Proposed event contract; no broker or producer is implemented by this baseline. +defaultContentType: application/cloudevents+json +channels: + relationshipChanged: + address: elunvera.relationship.changed.v1 + messages: + relationshipChanged: + $ref: '#/components/messages/RelationshipChanged' + opportunityStageChanged: + address: elunvera.opportunity.stage_changed.v1 + messages: + opportunityStageChanged: + $ref: '#/components/messages/OpportunityStageChanged' +operations: + consumeRelationshipChanged: + action: receive + channel: + $ref: '#/channels/relationshipChanged' + messages: + - $ref: '#/channels/relationshipChanged/messages/relationshipChanged' + consumeOpportunityStageChanged: + action: receive + channel: + $ref: '#/channels/opportunityStageChanged' + messages: + - $ref: '#/channels/opportunityStageChanged/messages/opportunityStageChanged' +components: + messages: + RelationshipChanged: + name: RelationshipChanged + title: Relationship changed CloudEvent + payload: + allOf: + - $ref: '#/components/schemas/CloudEventEnvelope' + - type: object + properties: + type: + const: org.contextualwisdomlab.elunvera.relationship.changed.v1 + data: + $ref: './events/relationship-changed-v1.schema.json' + OpportunityStageChanged: + name: OpportunityStageChanged + title: Opportunity stage changed CloudEvent + payload: + allOf: + - $ref: '#/components/schemas/CloudEventEnvelope' + - type: object + properties: + type: + const: org.contextualwisdomlab.elunvera.opportunity.stage_changed.v1 + data: + $ref: './events/opportunity-stage-changed-v1.schema.json' + schemas: + CloudEventEnvelope: + type: object + additionalProperties: true + required: [specversion, id, source, type, subject, time, datacontenttype, tenantref, correlationid, purposecode, data] + properties: + specversion: { const: '1.0' } + id: { type: string, format: uuid } + source: { type: string, format: uri-reference } + type: { type: string } + subject: { type: string, format: uri-reference } + time: { type: string, format: date-time } + datacontenttype: { const: application/json } + tenantref: { type: string, minLength: 8, maxLength: 500 } + correlationid: { type: string, minLength: 8, maxLength: 128 } + causationid: { type: [string, 'null'], maxLength: 128 } + provenanceref: { type: [string, 'null'], maxLength: 500 } + purposecode: { type: string, pattern: '^[a-z][a-z0-9_]{1,63}$' } + data: { type: object } diff --git a/schemas/events/opportunity-stage-changed-v1.schema.json b/schemas/events/opportunity-stage-changed-v1.schema.json new file mode 100644 index 0000000..0dddef1 --- /dev/null +++ b/schemas/events/opportunity-stage-changed-v1.schema.json @@ -0,0 +1,57 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.contextualwisdomlab.org/elunvera/events/opportunity-stage-changed-v1.schema.json", + "title": "ELUNVERA opportunity stage changed event data v1", + "type": "object", + "additionalProperties": false, + "required": [ + "opportunity_id", + "aggregate_version", + "sales_process_version_id", + "from_stage_definition_id", + "to_stage_definition_id", + "effective_at", + "reason_code" + ], + "properties": { + "opportunity_id": { + "type": "string", + "format": "uuid" + }, + "aggregate_version": { + "type": "integer", + "minimum": 1 + }, + "sales_process_version_id": { + "type": "string", + "format": "uuid" + }, + "from_stage_definition_id": { + "type": [ + "string", + "null" + ], + "format": "uuid" + }, + "to_stage_definition_id": { + "type": "string", + "format": "uuid" + }, + "effective_at": { + "type": "string", + "format": "date-time" + }, + "reason_code": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]{1,63}$" + }, + "evidence_reference_ids": { + "type": "array", + "maxItems": 100, + "items": { + "type": "string", + "format": "uuid" + } + } + } +} diff --git a/schemas/events/relationship-changed-v1.schema.json b/schemas/events/relationship-changed-v1.schema.json new file mode 100644 index 0000000..c788c4c --- /dev/null +++ b/schemas/events/relationship-changed-v1.schema.json @@ -0,0 +1,66 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.contextualwisdomlab.org/elunvera/events/relationship-changed-v1.schema.json", + "title": "ELUNVERA relationship changed event data v1", + "type": "object", + "additionalProperties": false, + "required": [ + "relationship_id", + "aggregate_version", + "truth_status", + "valid_from", + "participant_references", + "change_code" + ], + "properties": { + "relationship_id": { + "type": "string", + "format": "uuid" + }, + "aggregate_version": { + "type": "integer", + "minimum": 1 + }, + "truth_status": { + "enum": [ + "authoritative", + "observed", + "inferred", + "proposed", + "rejected", + "superseded", + "disputed" + ] + }, + "valid_from": { + "type": "string", + "format": "date-time" + }, + "valid_to": { + "type": [ + "string", + "null" + ], + "format": "date-time" + }, + "participant_references": { + "type": "array", + "minItems": 2, + "maxItems": 20, + "items": { + "type": "string", + "minLength": 8, + "maxLength": 500 + } + }, + "change_code": { + "enum": [ + "created", + "corrected", + "closed", + "reviewed", + "superseded" + ] + } + } +} diff --git a/schemas/openapi.yaml b/schemas/openapi.yaml new file mode 100644 index 0000000..dd3d6b1 --- /dev/null +++ b/schemas/openapi.yaml @@ -0,0 +1,275 @@ +openapi: 3.2.0 +info: + title: ELUNVERA API + version: 0.1.0 + summary: Evidence-centered CRM contract baseline + description: >- + Proposed HTTP contract. This repository baseline does not assert an implemented service. +servers: + - url: https://elunvera.invalid/v1 + description: Documentation-only placeholder domain; not a deployed service +security: + - keyverseBearer: [] +paths: + /accounts: + get: + operationId: listAccounts + summary: List tenant-scoped commercial accounts + parameters: + - $ref: '#/components/parameters/PageCursor' + - $ref: '#/components/parameters/PageSize' + responses: + '200': + description: Account page + content: + application/json: + schema: + $ref: '#/components/schemas/AccountPage' + default: + $ref: '#/components/responses/Problem' + post: + operationId: createAccount + summary: Create a commercial account + parameters: + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/CreateAccountRequest' + responses: + '201': + description: Created + headers: + ETag: + schema: { type: string } + content: + application/json: + schema: + $ref: '#/components/schemas/OperationReceipt' + default: + $ref: '#/components/responses/Problem' + /accounts/{account_id}: + parameters: + - $ref: '#/components/parameters/AccountId' + get: + operationId: getAccount + summary: Get an account under the active temporal lens + responses: + '200': + description: Account + headers: + ETag: + schema: { type: string } + content: + application/json: + schema: + $ref: '#/components/schemas/Account' + default: + $ref: '#/components/responses/Problem' + patch: + operationId: updateAccount + summary: Update an account using optimistic concurrency + parameters: + - $ref: '#/components/parameters/IdempotencyKey' + - $ref: '#/components/parameters/IfMatch' + requestBody: + required: true + content: + application/merge-patch+json: + schema: + $ref: '#/components/schemas/UpdateAccountRequest' + responses: + '200': + description: Updated + content: + application/json: + schema: + $ref: '#/components/schemas/OperationReceipt' + default: + $ref: '#/components/responses/Problem' + /relationships: + post: + operationId: recordRelationship + summary: Record a time-valid evidence-linked relationship + parameters: + - $ref: '#/components/parameters/IdempotencyKey' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/RecordRelationshipRequest' + responses: + '201': + description: Recorded + content: + application/json: + schema: + $ref: '#/components/schemas/OperationReceipt' + default: + $ref: '#/components/responses/Problem' + /opportunities/{opportunity_id}/stage-transitions: + post: + operationId: transitionOpportunityStage + summary: Append an opportunity stage transition + parameters: + - name: opportunity_id + in: path + required: true + schema: { type: string, format: uuid } + - $ref: '#/components/parameters/IdempotencyKey' + - $ref: '#/components/parameters/IfMatch' + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/StageTransitionRequest' + responses: + '200': + description: Transition committed + content: + application/json: + schema: + $ref: '#/components/schemas/OperationReceipt' + default: + $ref: '#/components/responses/Problem' +components: + securitySchemes: + keyverseBearer: + type: http + scheme: bearer + bearerFormat: JWT + parameters: + AccountId: + name: account_id + in: path + required: true + schema: { type: string, format: uuid } + IdempotencyKey: + name: Idempotency-Key + in: header + required: true + schema: { type: string, minLength: 16, maxLength: 128 } + IfMatch: + name: If-Match + in: header + required: true + schema: { type: string } + PageCursor: + name: cursor + in: query + required: false + schema: { type: [string, 'null'] } + PageSize: + name: page_size + in: query + required: false + schema: { type: integer, minimum: 1, maximum: 100, default: 50 } + responses: + Problem: + description: RFC 9457 problem + content: + application/problem+json: + schema: + $ref: '#/components/schemas/Problem' + schemas: + Account: + type: object + additionalProperties: false + required: [account_id, account_name, lifecycle_status, aggregate_version] + properties: + account_id: { type: string, format: uuid } + account_name: { type: string, minLength: 1, maxLength: 300 } + lifecycle_status: { type: string, enum: [prospective, active, inactive, closed] } + aggregate_version: { type: integer, minimum: 1 } + AccountPage: + type: object + additionalProperties: false + required: [items, next_cursor, page_size] + properties: + items: + type: array + items: { $ref: '#/components/schemas/Account' } + next_cursor: { type: [string, 'null'] } + page_size: { type: integer, minimum: 1, maximum: 100 } + CreateAccountRequest: + type: object + additionalProperties: false + required: [account_name, lifecycle_status] + properties: + account_name: { type: string, minLength: 1, maxLength: 300 } + lifecycle_status: { type: string, enum: [prospective, active] } + UpdateAccountRequest: + type: object + additionalProperties: false + minProperties: 1 + properties: + account_name: { type: string, minLength: 1, maxLength: 300 } + lifecycle_status: { type: string, enum: [prospective, active, inactive, closed] } + RecordRelationshipRequest: + type: object + additionalProperties: false + required: [relationship_type_version_id, participants, valid_from, truth_status] + properties: + relationship_type_version_id: { type: string, format: uuid } + participants: + type: array + minItems: 2 + maxItems: 20 + items: + type: object + additionalProperties: false + required: [party_id, role_code] + properties: + party_id: { type: string, format: uuid } + role_code: { type: string, pattern: '^[a-z][a-z0-9_]{1,63}$' } + valid_from: { type: string, format: date-time } + valid_to: { type: [string, 'null'], format: date-time } + truth_status: { type: string, enum: [authoritative, observed, inferred, proposed] } + evidence_reference_ids: + type: array + maxItems: 100 + items: { type: string, format: uuid } + manual_assertion_reason: { type: [string, 'null'], maxLength: 1000 } + anyOf: + - required: [evidence_reference_ids] + - required: [manual_assertion_reason] + StageTransitionRequest: + type: object + additionalProperties: false + required: [target_stage_definition_id, effective_at, reason_code] + properties: + target_stage_definition_id: { type: string, format: uuid } + effective_at: { type: string, format: date-time } + reason_code: { type: string, pattern: '^[a-z][a-z0-9_]{1,63}$' } + evidence_reference_ids: + type: array + maxItems: 100 + items: { type: string, format: uuid } + OperationReceipt: + type: object + additionalProperties: false + required: [operation_id, aggregate_reference, aggregate_version, recorded_at, event_reference, idempotency_status] + properties: + operation_id: { type: string, format: uuid } + aggregate_reference: { type: string, minLength: 8, maxLength: 500 } + aggregate_version: { type: integer, minimum: 1 } + recorded_at: { type: string, format: date-time } + event_reference: { type: string, minLength: 8, maxLength: 500 } + idempotency_status: { type: string, enum: [new, replayed] } + Problem: + type: object + additionalProperties: true + required: [type, title, status, error_code, correlation_id] + properties: + type: { type: string, format: uri-reference } + title: { type: string } + status: { type: integer, minimum: 400, maximum: 599 } + detail: { type: string } + instance: { type: string, format: uri-reference } + error_code: { type: string } + correlation_id: { type: string } + safe_next_action: { type: [string, 'null'] } From 1c31ca451a302421351738dc9ca33cd56f0cfce7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 05:04:49 -0700 Subject: [PATCH 16/87] ci: stage ELUNVERA contract repair patch --- .bootstrap/contract-fix.patch.gz.b64 | 1 + 1 file changed, 1 insertion(+) create mode 100644 .bootstrap/contract-fix.patch.gz.b64 diff --git a/.bootstrap/contract-fix.patch.gz.b64 b/.bootstrap/contract-fix.patch.gz.b64 new file mode 100644 index 0000000..5ae7194 --- /dev/null +++ b/.bootstrap/contract-fix.patch.gz.b64 @@ -0,0 +1 @@ +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 \ No newline at end of file From 3572e83ad67aca0b768ada8de773e94df52f197d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 05:07:56 -0700 Subject: [PATCH 17/87] ci: run bounded ELUNVERA contract repair --- .../workflows/repair-contract-coherence.yml | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 .github/workflows/repair-contract-coherence.yml diff --git a/.github/workflows/repair-contract-coherence.yml b/.github/workflows/repair-contract-coherence.yml new file mode 100644 index 0000000..380c33d --- /dev/null +++ b/.github/workflows/repair-contract-coherence.yml @@ -0,0 +1,149 @@ +name: Repair ELUNVERA contract coherence + +on: + push: + branches: + - docs/product-technical-baseline + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: elunvera-contract-coherence-repair + cancel-in-progress: false + +jobs: + repair: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out exact feature branch + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + ref: docs/product-technical-baseline + fetch-depth: 0 + + - name: Verify preimage, apply bounded patch, and validate contracts + shell: bash + run: | + set -euo pipefail + + cat > /tmp/preimage.sha256 <<'EOF' + 335c872458d18069fd76569b0eb49ff1062c6f6b44ef2ba58e714e207ab1f098 CHANGELOG.md + 8c23a286938b7e44c5e6990104b249fe4dabb499f47f38566407cb324ddd7170 docs/API_CONTRACT.md + 13f332255239f79e773bcce00a6b19a2051ff5cb7273ae0e24ca6413a38ea0fc docs/TRD.md + 116e9549728e8b374ee492ad622ade97eec33e4bfc49d0b3e238109af1ef512c docs/VALIDATION_REPORT.md + 2670697f82e5046f07e9938bae12f95f59bba7c66113990a826820149b8b00a6 schemas/asyncapi.yaml + 1a65236b1a0703abbe74c568692c851336393c62e84e6977f13356a5a16f03b1 schemas/events/opportunity-stage-changed-v1.schema.json + 5bd9b1504d8c1ad1c9c3df4cd1d8a39e31b4fc15a10633707da222be6814dcb0 schemas/events/relationship-changed-v1.schema.json + 03adaef269648275bd5d9e44d99a7f990f18efbf05a40771b628b971de79e8fb schemas/openapi.yaml + bdabc6bb01216905f6bac94520c4f3e8d5206984744846ba764be7f70b4b2104 manifest.json + EOF + sha256sum --check /tmp/preimage.sha256 + + tr -d '\n\r\t ' < .bootstrap/contract-fix.patch.gz.b64 \ + | base64 --decode \ + | gzip -d > /tmp/contract-fix.patch + echo "60663ec230643acf1a6fefd7a56a0cff8f29b2831b9bdfecfdf92db073b4bd62 /tmp/contract-fix.patch" \ + | sha256sum --check - + git apply --check /tmp/contract-fix.patch + git apply /tmp/contract-fix.patch + + ruby <<'RUBY' + require 'yaml' + + openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) + raise 'OpenAPI version mismatch' unless openapi['openapi'] == '3.2.0' + + methods = %w[get post put patch delete options head trace] + operations = [] + openapi.fetch('paths').each do |path, item| + item.each do |method, operation| + next unless methods.include?(method) + operations << [method.upcase, "/v1#{path}", operation.fetch('operationId')] + end + end + expected = [ + ['GET', '/v1/accounts'], + ['POST', '/v1/accounts'], + ['GET', '/v1/accounts/{account_id}'], + ['PATCH', '/v1/accounts/{account_id}'], + ['POST', '/v1/relationships'], + ['POST', '/v1/opportunities/{opportunity_id}/stage-transitions'] + ].sort + raise 'OpenAPI/narrative operation parity mismatch' unless operations.map { |method, path, _| [method, path] }.sort == expected + raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length + + ['/accounts', '/accounts/{account_id}'].each do |path| + operation = openapi.fetch('paths').fetch(path).fetch('get') + refs = operation.fetch('parameters').filter_map { |parameter| parameter['$ref'] } + %w[ValidAt RecordedAt KnowledgeCutoff].each do |name| + raise "missing temporal parameter #{name}" unless refs.include?("#/components/parameters/#{name}") + end + headers = operation.fetch('responses').fetch('200').fetch('headers') + %w[X-ELUNVERA-Valid-At X-ELUNVERA-Recorded-At X-ELUNVERA-Knowledge-Cutoff].each do |name| + raise "missing temporal response header #{name}" unless headers.key?(name) + end + end + + openapi.fetch('paths').each do |_path, item| + item.each do |method, operation| + next unless %w[post patch put delete].include?(method) + refs = operation.fetch('parameters').filter_map { |parameter| parameter['$ref'] } + raise 'missing correlation ID' unless refs.include?('#/components/parameters/CorrelationId') + raise 'missing idempotency key' unless refs.include?('#/components/parameters/IdempotencyKey') + end + end + + asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) + raise 'AsyncAPI version mismatch' unless asyncapi['asyncapi'] == '3.1.0' + expected_operations = %w[publishOpportunityStageChanged publishRelationshipChanged] + raise 'AsyncAPI operation set mismatch' unless asyncapi.fetch('operations').keys.sort == expected_operations + raise 'AsyncAPI producer direction mismatch' unless asyncapi.fetch('operations').values.all? { |operation| operation['action'] == 'send' } + envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') + %w[dataclassification schemarevision].each do |name| + raise "missing envelope metadata #{name}" unless envelope.fetch('required').include?(name) + end + RUBY + + python3 <<'PY' + import hashlib + import json + from pathlib import Path + + for event_path in ( + Path('schemas/events/relationship-changed-v1.schema.json'), + Path('schemas/events/opportunity-stage-changed-v1.schema.json'), + ): + schema = json.loads(event_path.read_text(encoding='utf-8')) + assert 'recorded_at' in schema['required'], event_path + assert schema['properties']['recorded_at']['format'] == 'date-time', event_path + + manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) + assert manifest['file_count'] == len(manifest['files']) == 54 + for entry in manifest['files']: + path = Path(entry['path']) + payload = path.read_bytes() + assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path + assert len(payload) == entry['size_bytes'], path + assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path + PY + + test "$(git ls-files | wc -l)" -eq 57 + git diff --check + + - name: Commit verified repair and remove transfer artifacts + shell: bash + run: | + set -euo pipefail + rm -rf .bootstrap + rm -f .github/workflows/repair-contract-coherence.yml + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + test "$(git ls-files --cached | wc -l)" -eq 55 + git commit -m "fix: align HTTP and event contract coherence" + git push origin HEAD:docs/product-technical-baseline From 3eab23a43038515850e34321a5de45b7e1422d93 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 29 Aug 2026 12:08:17 +0000 Subject: [PATCH 18/87] fix: align HTTP and event contract coherence --- .bootstrap/contract-fix.patch.gz.b64 | 1 - .../workflows/repair-contract-coherence.yml | 149 ------- CHANGELOG.md | 7 + docs/API_CONTRACT.md | 87 +--- docs/TRD.md | 7 +- docs/VALIDATION_REPORT.md | 8 +- manifest.json | 50 +-- schemas/asyncapi.yaml | 118 ++++-- .../opportunity-stage-changed-v1.schema.json | 6 + .../relationship-changed-v1.schema.json | 6 + schemas/openapi.yaml | 373 ++++++++++++++---- 11 files changed, 453 insertions(+), 359 deletions(-) delete mode 100644 .bootstrap/contract-fix.patch.gz.b64 delete mode 100644 .github/workflows/repair-contract-coherence.yml diff --git a/.bootstrap/contract-fix.patch.gz.b64 b/.bootstrap/contract-fix.patch.gz.b64 deleted file mode 100644 index 5ae7194..0000000 --- a/.bootstrap/contract-fix.patch.gz.b64 +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/.github/workflows/repair-contract-coherence.yml b/.github/workflows/repair-contract-coherence.yml deleted file mode 100644 index 380c33d..0000000 --- a/.github/workflows/repair-contract-coherence.yml +++ /dev/null @@ -1,149 +0,0 @@ -name: Repair ELUNVERA contract coherence - -on: - push: - branches: - - docs/product-technical-baseline - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: elunvera-contract-coherence-repair - cancel-in-progress: false - -jobs: - repair: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out exact feature branch - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - ref: docs/product-technical-baseline - fetch-depth: 0 - - - name: Verify preimage, apply bounded patch, and validate contracts - shell: bash - run: | - set -euo pipefail - - cat > /tmp/preimage.sha256 <<'EOF' - 335c872458d18069fd76569b0eb49ff1062c6f6b44ef2ba58e714e207ab1f098 CHANGELOG.md - 8c23a286938b7e44c5e6990104b249fe4dabb499f47f38566407cb324ddd7170 docs/API_CONTRACT.md - 13f332255239f79e773bcce00a6b19a2051ff5cb7273ae0e24ca6413a38ea0fc docs/TRD.md - 116e9549728e8b374ee492ad622ade97eec33e4bfc49d0b3e238109af1ef512c docs/VALIDATION_REPORT.md - 2670697f82e5046f07e9938bae12f95f59bba7c66113990a826820149b8b00a6 schemas/asyncapi.yaml - 1a65236b1a0703abbe74c568692c851336393c62e84e6977f13356a5a16f03b1 schemas/events/opportunity-stage-changed-v1.schema.json - 5bd9b1504d8c1ad1c9c3df4cd1d8a39e31b4fc15a10633707da222be6814dcb0 schemas/events/relationship-changed-v1.schema.json - 03adaef269648275bd5d9e44d99a7f990f18efbf05a40771b628b971de79e8fb schemas/openapi.yaml - bdabc6bb01216905f6bac94520c4f3e8d5206984744846ba764be7f70b4b2104 manifest.json - EOF - sha256sum --check /tmp/preimage.sha256 - - tr -d '\n\r\t ' < .bootstrap/contract-fix.patch.gz.b64 \ - | base64 --decode \ - | gzip -d > /tmp/contract-fix.patch - echo "60663ec230643acf1a6fefd7a56a0cff8f29b2831b9bdfecfdf92db073b4bd62 /tmp/contract-fix.patch" \ - | sha256sum --check - - git apply --check /tmp/contract-fix.patch - git apply /tmp/contract-fix.patch - - ruby <<'RUBY' - require 'yaml' - - openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) - raise 'OpenAPI version mismatch' unless openapi['openapi'] == '3.2.0' - - methods = %w[get post put patch delete options head trace] - operations = [] - openapi.fetch('paths').each do |path, item| - item.each do |method, operation| - next unless methods.include?(method) - operations << [method.upcase, "/v1#{path}", operation.fetch('operationId')] - end - end - expected = [ - ['GET', '/v1/accounts'], - ['POST', '/v1/accounts'], - ['GET', '/v1/accounts/{account_id}'], - ['PATCH', '/v1/accounts/{account_id}'], - ['POST', '/v1/relationships'], - ['POST', '/v1/opportunities/{opportunity_id}/stage-transitions'] - ].sort - raise 'OpenAPI/narrative operation parity mismatch' unless operations.map { |method, path, _| [method, path] }.sort == expected - raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length - - ['/accounts', '/accounts/{account_id}'].each do |path| - operation = openapi.fetch('paths').fetch(path).fetch('get') - refs = operation.fetch('parameters').filter_map { |parameter| parameter['$ref'] } - %w[ValidAt RecordedAt KnowledgeCutoff].each do |name| - raise "missing temporal parameter #{name}" unless refs.include?("#/components/parameters/#{name}") - end - headers = operation.fetch('responses').fetch('200').fetch('headers') - %w[X-ELUNVERA-Valid-At X-ELUNVERA-Recorded-At X-ELUNVERA-Knowledge-Cutoff].each do |name| - raise "missing temporal response header #{name}" unless headers.key?(name) - end - end - - openapi.fetch('paths').each do |_path, item| - item.each do |method, operation| - next unless %w[post patch put delete].include?(method) - refs = operation.fetch('parameters').filter_map { |parameter| parameter['$ref'] } - raise 'missing correlation ID' unless refs.include?('#/components/parameters/CorrelationId') - raise 'missing idempotency key' unless refs.include?('#/components/parameters/IdempotencyKey') - end - end - - asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) - raise 'AsyncAPI version mismatch' unless asyncapi['asyncapi'] == '3.1.0' - expected_operations = %w[publishOpportunityStageChanged publishRelationshipChanged] - raise 'AsyncAPI operation set mismatch' unless asyncapi.fetch('operations').keys.sort == expected_operations - raise 'AsyncAPI producer direction mismatch' unless asyncapi.fetch('operations').values.all? { |operation| operation['action'] == 'send' } - envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') - %w[dataclassification schemarevision].each do |name| - raise "missing envelope metadata #{name}" unless envelope.fetch('required').include?(name) - end - RUBY - - python3 <<'PY' - import hashlib - import json - from pathlib import Path - - for event_path in ( - Path('schemas/events/relationship-changed-v1.schema.json'), - Path('schemas/events/opportunity-stage-changed-v1.schema.json'), - ): - schema = json.loads(event_path.read_text(encoding='utf-8')) - assert 'recorded_at' in schema['required'], event_path - assert schema['properties']['recorded_at']['format'] == 'date-time', event_path - - manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) - assert manifest['file_count'] == len(manifest['files']) == 54 - for entry in manifest['files']: - path = Path(entry['path']) - payload = path.read_bytes() - assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path - assert len(payload) == entry['size_bytes'], path - assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path - PY - - test "$(git ls-files | wc -l)" -eq 57 - git diff --check - - - name: Commit verified repair and remove transfer artifacts - shell: bash - run: | - set -euo pipefail - rm -rf .bootstrap - rm -f .github/workflows/repair-contract-coherence.yml - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - test "$(git ls-files --cached | wc -l)" -eq 55 - git commit -m "fix: align HTTP and event contract coherence" - git push origin HEAD:docs/product-technical-baseline diff --git a/CHANGELOG.md b/CHANGELOG.md index 30ba533..50a0cbd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,13 @@ The format follows Keep a Changelog principles, and versioning will begin when t - OpenAPI 3.2.0 and AsyncAPI 3.1.0 draft contracts. - Initial product-technical gap baseline and phased implementation plan. +### Fixed + +- Aligned the narrative HTTP inventory with the authoritative OpenAPI P0 surface. +- Added temporal read parameters and effective-lens response headers to the machine-readable HTTP contract. +- Corrected AsyncAPI operations to publish ELUNVERA domain events and required classification/schema metadata. +- Added explicit `recorded_at` payload fields so outbox publication delay cannot corrupt bitemporal reconstruction. + ### Security - Defined fail-closed tenant isolation, purpose-aware authorization, immutable audit, model provenance, controlled egress, and customer-data disclosure boundaries. diff --git a/docs/API_CONTRACT.md b/docs/API_CONTRACT.md index bae3001..8074c84 100644 --- a/docs/API_CONTRACT.md +++ b/docs/API_CONTRACT.md @@ -113,91 +113,24 @@ Every non-success response uses RFC 9457 fields and ELUNVERA extensions: Messages help the user take the next action and never expose SQL, internal service names, stack traces, secrets, or cross-tenant existence. -## 6. Resource endpoints +## 6. Contract-bearing P0 endpoints -The initial contract surface is deliberately narrow. - -### Accounts +The authoritative P0 HTTP surface is exactly the set of operations present in `schemas/openapi.yaml`: ```text +GET /v1/accounts POST /v1/accounts GET /v1/accounts/{account_id} PATCH /v1/accounts/{account_id} -GET /v1/accounts -GET /v1/accounts/{account_id}/timeline -GET /v1/accounts/{account_id}/relationships -POST /v1/accounts/{account_id}/merge-jobs -POST /v1/accounts/{account_id}/split-jobs -``` - -### Parties and relationships - -```text -POST /v1/parties -GET /v1/parties/{party_id} -PATCH /v1/parties/{party_id} POST /v1/relationships -GET /v1/relationships/{relationship_id} -PATCH /v1/relationships/{relationship_id} -POST /v1/relationships/{relationship_id}/review-decisions -``` - -### Interactions and commitments - -```text -POST /v1/interactions -GET /v1/interactions/{interaction_id} -POST /v1/commitments -PATCH /v1/commitments/{commitment_id} -POST /v1/commitments/{commitment_id}/transitions -``` - -### Opportunities - -```text -POST /v1/opportunities -GET /v1/opportunities/{opportunity_id} -PATCH /v1/opportunities/{opportunity_id} POST /v1/opportunities/{opportunity_id}/stage-transitions -POST /v1/opportunities/{opportunity_id}/value-snapshots -POST /v1/opportunities/{opportunity_id}/forecast-snapshots ``` -### Customer outcomes and complaints - -```text -POST /v1/customer-outcomes -GET /v1/customer-outcomes/{outcome_id} -POST /v1/complaints -GET /v1/complaints/{complaint_id} -POST /v1/complaints/{complaint_id}/transitions -POST /v1/satisfaction-observations -``` +The two account read operations accept the contract-defined `valid_at`, `recorded_at`, and `knowledge_cutoff` parameters and echo the effective temporal lens in response headers. Mutations require `X-Correlation-Id` and `Idempotency-Key`; updates to an existing aggregate also require `If-Match`. -### Search and proposed intelligence - -```text -POST /v1/search-queries -POST /v1/context-bundles -POST /v1/model-jobs -GET /v1/model-jobs/{job_id} -POST /v1/model-claims/{claim_id}/review-decisions -``` +Parties, interactions, commitments, relationship review, account merge/split, customer outcomes, complaints, satisfaction observations, search, model jobs, privacy cases, disposition, legal hold, and audit-query operations remain product-roadmap candidates. They are **not** HTTP contract commitments until their operations and schemas are added to `schemas/openapi.yaml`, validated, and versioned. -Model endpoints return evidence references, uncertainty, model identity, prompt hash, and review status. A model claim cannot mutate authoritative CRM facts. - -### Privacy and audit - -```text -POST /v1/data-rights-cases -GET /v1/data-rights-cases/{case_id} -POST /v1/data-rights-cases/{case_id}/exports -POST /v1/disposition-jobs -POST /v1/legal-holds -GET /v1/audit-events -``` - -Audit search is purpose-restricted and paginated. Export manifests identify included and excluded fields, source authority, and policy reason. +Model-related future operations must return evidence references, uncertainty, model identity, prompt hash, and review status. A model claim can never mutate authoritative CRM facts without an explicit human-reviewed command. ## 7. Command receipts @@ -234,12 +167,18 @@ Domain events include the CloudEvents core fields plus bounded extensions: "causationid": "019d...", "provenanceref": "urn:elunvera:evidence:019d...", "purposecode": "account_management", - "data": {} + "dataclassification": "restricted_personal_and_commercial", + "schemarevision": "1.0.0", + "data": { + "recorded_at": "2026-08-27T08:59:58Z" + } } ``` Events never contain passwords, tokens, raw email bodies, unrestricted notes, unnecessary contact details, or provider secrets. +`time` is the CloudEvent publication time. Payloads that carry bitemporal facts include an explicit immutable `recorded_at`, because an outbox or broker delay can make publication time later than the system-recorded time. The internal metadata names `data_classification` and `schema_revision` serialize as the CloudEvents extension attributes `dataclassification` and `schemarevision`. + ## 9. Initial event types ```text diff --git a/docs/TRD.md b/docs/TRD.md index 2bd4efa..23ebf4a 100644 --- a/docs/TRD.md +++ b/docs/TRD.md @@ -229,10 +229,13 @@ tenantref correlationid causationid provenanceref -data_classification -schema_revision +purposecode +dataclassification +schemarevision ``` +The internal metadata names `data_classification` and `schema_revision` serialize as the wire attributes `dataclassification` and `schemarevision`. `time` is publication time. Event payloads that describe bitemporal facts also require an immutable `recorded_at`; consumers must not substitute publication time for system-recorded time. + Events contain opaque references and minimum necessary data. Consumers retrieve authorized details from the owning API. ## 10. Search and relationship projection diff --git a/docs/VALIDATION_REPORT.md b/docs/VALIDATION_REPORT.md index e3d0f58..abac821 100644 --- a/docs/VALIDATION_REPORT.md +++ b/docs/VALIDATION_REPORT.md @@ -16,7 +16,11 @@ | JSON Schema Draft 2020-12 metaschema validation | Pass | | YAML parsing | Pass | | OpenAPI version and unique `operationId` structure | Pass | -| AsyncAPI version, channel, and operation structure | Pass | +| Narrative/OpenAPI operation parity for the contract-bearing P0 surface | Pass | +| Temporal query parameters and effective-lens response headers | Pass | +| AsyncAPI version, channel, producer-operation direction, and message structure | Pass | +| Required event classification and payload-schema revision metadata | Pass | +| Explicit bitemporal `recorded_at` in domain-event payloads | Pass | | Placeholder-token scan | Pass | | Obvious database two-word `snake_case` declaration check | Pass | | Manifest SHA-256 verification | Pass after manifest generation | @@ -34,7 +38,7 @@ ```text Python JSON and JSON Schema validation PyYAML parsing -OpenAPI/AsyncAPI structural checks +OpenAPI/AsyncAPI structural and cross-contract coherence checks Markdown relative-link and fence checks Placeholder and naming scans SHA-256 manifest generation and verification diff --git a/manifest.json b/manifest.json index f18c217..8fbd2b7 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "schema_version": "1.0", "product": "ELUNVERA", - "generated_at": "2026-08-27T00:00:00Z", + "generated_at": "2026-08-29T00:00:00Z", "algorithm": "SHA-256", "self_excluded": true, "file_count": 54, @@ -26,9 +26,9 @@ }, { "path": "CHANGELOG.md", - "sha256": "335c872458d18069fd76569b0eb49ff1062c6f6b44ef2ba58e714e207ab1f098", - "size_bytes": 1154, - "line_count": 24 + "sha256": "e156a07dcc8e31ab59c8145a192eb1c2edaca9d2f2ffd672f6e9c339b704e893", + "size_bytes": 1583, + "line_count": 31 }, { "path": "CLAUDE.md", @@ -56,9 +56,9 @@ }, { "path": "docs/API_CONTRACT.md", - "sha256": "8c23a286938b7e44c5e6990104b249fe4dabb499f47f38566407cb324ddd7170", - "size_bytes": 9253, - "line_count": 287 + "sha256": "82f5d44989a1d7000dd586dde95ad71e00f52aec05d053bacbebd5f22988cfb5", + "size_bytes": 8811, + "line_count": 226 }, { "path": "docs/ARCHITECTURE.md", @@ -128,9 +128,9 @@ }, { "path": "docs/TRD.md", - "sha256": "13f332255239f79e773bcce00a6b19a2051ff5cb7273ae0e24ca6413a38ea0fc", - "size_bytes": 14747, - "line_count": 342 + "sha256": "c069df7a0d0f2a955eefeea39b87004ab351a75cae6dba4e65c29856f162af78", + "size_bytes": 15094, + "line_count": 345 }, { "path": "docs/UML.md", @@ -158,9 +158,9 @@ }, { "path": "docs/VALIDATION_REPORT.md", - "sha256": "116e9549728e8b374ee492ad622ade97eec33e4bfc49d0b3e238109af1ef512c", - "size_bytes": 2008, - "line_count": 49 + "sha256": "c5a40ac8c25e8beea60a665f943f15ae4dfe12f60a96258b7a74047731fa2f82", + "size_bytes": 2368, + "line_count": 53 }, { "path": "docs/WIREFRAMES.md", @@ -308,27 +308,27 @@ }, { "path": "schemas/asyncapi.yaml", - "sha256": "2670697f82e5046f07e9938bae12f95f59bba7c66113990a826820149b8b00a6", - "size_bytes": 2837, - "line_count": 75 + "sha256": "6114f1df68a25182dd454903a77e8da343f0c343ca51d0162163a87f56c4fb42", + "size_bytes": 3572, + "line_count": 125 }, { "path": "schemas/events/opportunity-stage-changed-v1.schema.json", - "sha256": "1a65236b1a0703abbe74c568692c851336393c62e84e6977f13356a5a16f03b1", - "size_bytes": 1299, - "line_count": 57 + "sha256": "03c3ac79ffe93f518255401c12cc809eda31b4b5623bdc81474f44dcc8bf28b8", + "size_bytes": 1486, + "line_count": 63 }, { "path": "schemas/events/relationship-changed-v1.schema.json", - "sha256": "5bd9b1504d8c1ad1c9c3df4cd1d8a39e31b4fc15a10633707da222be6814dcb0", - "size_bytes": 1358, - "line_count": 66 + "sha256": "bfcb12a02e472b74a20152a5671f5ebf18d80389a8bbe466e289873645a4945f", + "size_bytes": 1545, + "line_count": 72 }, { "path": "schemas/openapi.yaml", - "sha256": "03adaef269648275bd5d9e44d99a7f990f18efbf05a40771b628b971de79e8fb", - "size_bytes": 9293, - "line_count": 275 + "sha256": "0e31e63c4c3e2bd95d58c7a17b064f106ca807a1a83d086af01641c2cfecff3b", + "size_bytes": 13246, + "line_count": 504 } ] } diff --git a/schemas/asyncapi.yaml b/schemas/asyncapi.yaml index 8c1f7c3..664e4e9 100644 --- a/schemas/asyncapi.yaml +++ b/schemas/asyncapi.yaml @@ -16,18 +16,18 @@ channels: opportunityStageChanged: $ref: '#/components/messages/OpportunityStageChanged' operations: - consumeRelationshipChanged: - action: receive + publishRelationshipChanged: + action: send channel: $ref: '#/channels/relationshipChanged' messages: - - $ref: '#/channels/relationshipChanged/messages/relationshipChanged' - consumeOpportunityStageChanged: - action: receive + - $ref: '#/channels/relationshipChanged/messages/relationshipChanged' + publishOpportunityStageChanged: + action: send channel: $ref: '#/channels/opportunityStageChanged' messages: - - $ref: '#/channels/opportunityStageChanged/messages/opportunityStageChanged' + - $ref: '#/channels/opportunityStageChanged/messages/opportunityStageChanged' components: messages: RelationshipChanged: @@ -35,41 +35,91 @@ components: title: Relationship changed CloudEvent payload: allOf: - - $ref: '#/components/schemas/CloudEventEnvelope' - - type: object - properties: - type: - const: org.contextualwisdomlab.elunvera.relationship.changed.v1 - data: - $ref: './events/relationship-changed-v1.schema.json' + - $ref: '#/components/schemas/CloudEventEnvelope' + - type: object + properties: + type: + const: org.contextualwisdomlab.elunvera.relationship.changed.v1 + data: + $ref: ./events/relationship-changed-v1.schema.json OpportunityStageChanged: name: OpportunityStageChanged title: Opportunity stage changed CloudEvent payload: allOf: - - $ref: '#/components/schemas/CloudEventEnvelope' - - type: object - properties: - type: - const: org.contextualwisdomlab.elunvera.opportunity.stage_changed.v1 - data: - $ref: './events/opportunity-stage-changed-v1.schema.json' + - $ref: '#/components/schemas/CloudEventEnvelope' + - type: object + properties: + type: + const: org.contextualwisdomlab.elunvera.opportunity.stage_changed.v1 + data: + $ref: ./events/opportunity-stage-changed-v1.schema.json schemas: CloudEventEnvelope: type: object additionalProperties: true - required: [specversion, id, source, type, subject, time, datacontenttype, tenantref, correlationid, purposecode, data] + required: + - specversion + - id + - source + - type + - subject + - time + - datacontenttype + - tenantref + - correlationid + - purposecode + - dataclassification + - schemarevision + - data properties: - specversion: { const: '1.0' } - id: { type: string, format: uuid } - source: { type: string, format: uri-reference } - type: { type: string } - subject: { type: string, format: uri-reference } - time: { type: string, format: date-time } - datacontenttype: { const: application/json } - tenantref: { type: string, minLength: 8, maxLength: 500 } - correlationid: { type: string, minLength: 8, maxLength: 128 } - causationid: { type: [string, 'null'], maxLength: 128 } - provenanceref: { type: [string, 'null'], maxLength: 500 } - purposecode: { type: string, pattern: '^[a-z][a-z0-9_]{1,63}$' } - data: { type: object } + specversion: + const: '1.0' + id: + type: string + format: uuid + source: + type: string + format: uri-reference + type: + type: string + subject: + type: string + format: uri-reference + time: + type: string + format: date-time + description: CloudEvent publication time; not a substitute for payload recorded_at. + datacontenttype: + const: application/json + tenantref: + type: string + minLength: 8 + maxLength: 500 + correlationid: + type: string + minLength: 8 + maxLength: 128 + causationid: + type: + - string + - 'null' + maxLength: 128 + provenanceref: + type: + - string + - 'null' + maxLength: 500 + purposecode: + type: string + pattern: ^[a-z][a-z0-9_]{1,63}$ + data: + type: object + dataclassification: + type: string + pattern: ^[a-z][a-z0-9_]{1,63}$ + description: Minimum handling classification for the complete event. + schemarevision: + type: string + pattern: ^[1-9][0-9]*\.[0-9]+\.[0-9]+$ + description: Semantic version of the payload schema revision. diff --git a/schemas/events/opportunity-stage-changed-v1.schema.json b/schemas/events/opportunity-stage-changed-v1.schema.json index 0dddef1..0c074be 100644 --- a/schemas/events/opportunity-stage-changed-v1.schema.json +++ b/schemas/events/opportunity-stage-changed-v1.schema.json @@ -7,6 +7,7 @@ "required": [ "opportunity_id", "aggregate_version", + "recorded_at", "sales_process_version_id", "from_stage_definition_id", "to_stage_definition_id", @@ -22,6 +23,11 @@ "type": "integer", "minimum": 1 }, + "recorded_at": { + "type": "string", + "format": "date-time", + "description": "Immutable system time when this aggregate version was recorded." + }, "sales_process_version_id": { "type": "string", "format": "uuid" diff --git a/schemas/events/relationship-changed-v1.schema.json b/schemas/events/relationship-changed-v1.schema.json index c788c4c..f8aa916 100644 --- a/schemas/events/relationship-changed-v1.schema.json +++ b/schemas/events/relationship-changed-v1.schema.json @@ -7,6 +7,7 @@ "required": [ "relationship_id", "aggregate_version", + "recorded_at", "truth_status", "valid_from", "participant_references", @@ -21,6 +22,11 @@ "type": "integer", "minimum": 1 }, + "recorded_at": { + "type": "string", + "format": "date-time", + "description": "Immutable system time when this aggregate version was recorded." + }, "truth_status": { "enum": [ "authoritative", diff --git a/schemas/openapi.yaml b/schemas/openapi.yaml index dd3d6b1..672a16e 100644 --- a/schemas/openapi.yaml +++ b/schemas/openapi.yaml @@ -3,21 +3,23 @@ info: title: ELUNVERA API version: 0.1.0 summary: Evidence-centered CRM contract baseline - description: >- - Proposed HTTP contract. This repository baseline does not assert an implemented service. + description: Proposed HTTP contract. This repository baseline does not assert an implemented service. servers: - - url: https://elunvera.invalid/v1 - description: Documentation-only placeholder domain; not a deployed service +- url: https://elunvera.invalid/v1 + description: Documentation-only placeholder domain; not a deployed service security: - - keyverseBearer: [] +- keyverseBearer: [] paths: /accounts: get: operationId: listAccounts summary: List tenant-scoped commercial accounts parameters: - - $ref: '#/components/parameters/PageCursor' - - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/PageCursor' + - $ref: '#/components/parameters/PageSize' + - $ref: '#/components/parameters/ValidAt' + - $ref: '#/components/parameters/RecordedAt' + - $ref: '#/components/parameters/KnowledgeCutoff' responses: '200': description: Account page @@ -25,13 +27,21 @@ paths: application/json: schema: $ref: '#/components/schemas/AccountPage' + headers: + X-ELUNVERA-Valid-At: + $ref: '#/components/headers/EffectiveValidAt' + X-ELUNVERA-Recorded-At: + $ref: '#/components/headers/EffectiveRecordedAt' + X-ELUNVERA-Knowledge-Cutoff: + $ref: '#/components/headers/EffectiveKnowledgeCutoff' default: $ref: '#/components/responses/Problem' post: operationId: createAccount summary: Create a commercial account parameters: - - $ref: '#/components/parameters/IdempotencyKey' + - $ref: '#/components/parameters/CorrelationId' + - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: @@ -43,7 +53,8 @@ paths: description: Created headers: ETag: - schema: { type: string } + schema: + type: string content: application/json: schema: @@ -52,7 +63,7 @@ paths: $ref: '#/components/responses/Problem' /accounts/{account_id}: parameters: - - $ref: '#/components/parameters/AccountId' + - $ref: '#/components/parameters/AccountId' get: operationId: getAccount summary: Get an account under the active temporal lens @@ -61,19 +72,31 @@ paths: description: Account headers: ETag: - schema: { type: string } + schema: + type: string + X-ELUNVERA-Valid-At: + $ref: '#/components/headers/EffectiveValidAt' + X-ELUNVERA-Recorded-At: + $ref: '#/components/headers/EffectiveRecordedAt' + X-ELUNVERA-Knowledge-Cutoff: + $ref: '#/components/headers/EffectiveKnowledgeCutoff' content: application/json: schema: $ref: '#/components/schemas/Account' default: $ref: '#/components/responses/Problem' + parameters: + - $ref: '#/components/parameters/ValidAt' + - $ref: '#/components/parameters/RecordedAt' + - $ref: '#/components/parameters/KnowledgeCutoff' patch: operationId: updateAccount summary: Update an account using optimistic concurrency parameters: - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/IfMatch' + - $ref: '#/components/parameters/CorrelationId' + - $ref: '#/components/parameters/IdempotencyKey' + - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: @@ -87,6 +110,11 @@ paths: application/json: schema: $ref: '#/components/schemas/OperationReceipt' + headers: + ETag: + description: Entity tag for the resulting aggregate version. + schema: + type: string default: $ref: '#/components/responses/Problem' /relationships: @@ -94,7 +122,8 @@ paths: operationId: recordRelationship summary: Record a time-valid evidence-linked relationship parameters: - - $ref: '#/components/parameters/IdempotencyKey' + - $ref: '#/components/parameters/CorrelationId' + - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: @@ -115,12 +144,15 @@ paths: operationId: transitionOpportunityStage summary: Append an opportunity stage transition parameters: - - name: opportunity_id - in: path - required: true - schema: { type: string, format: uuid } - - $ref: '#/components/parameters/IdempotencyKey' - - $ref: '#/components/parameters/IfMatch' + - name: opportunity_id + in: path + required: true + schema: + type: string + format: uuid + - $ref: '#/components/parameters/CorrelationId' + - $ref: '#/components/parameters/IdempotencyKey' + - $ref: '#/components/parameters/IfMatch' requestBody: required: true content: @@ -147,27 +179,79 @@ components: name: account_id in: path required: true - schema: { type: string, format: uuid } + schema: + type: string + format: uuid IdempotencyKey: name: Idempotency-Key in: header required: true - schema: { type: string, minLength: 16, maxLength: 128 } + schema: + type: string + minLength: 16 + maxLength: 128 IfMatch: name: If-Match in: header required: true - schema: { type: string } + schema: + type: string PageCursor: name: cursor in: query required: false - schema: { type: [string, 'null'] } + schema: + type: + - string + - 'null' PageSize: name: page_size in: query required: false - schema: { type: integer, minimum: 1, maximum: 100, default: 50 } + schema: + type: integer + minimum: 1 + maximum: 100 + default: 50 + CorrelationId: + name: X-Correlation-Id + in: header + required: true + description: Stable request correlation identifier generated by the caller. + schema: + type: string + minLength: 16 + maxLength: 128 + ValidAt: + name: valid_at + in: query + required: false + description: Business-valid instant used to select time-valid facts. + schema: + type: + - string + - 'null' + format: date-time + RecordedAt: + name: recorded_at + in: query + required: false + description: System-recorded instant used to reconstruct what ELUNVERA knew. + schema: + type: + - string + - 'null' + format: date-time + KnowledgeCutoff: + name: knowledge_cutoff + in: query + required: false + description: Latest recorded instant whose facts may contribute to this response. + schema: + type: + - string + - 'null' + format: date-time responses: Problem: description: RFC 9457 problem @@ -179,42 +263,93 @@ components: Account: type: object additionalProperties: false - required: [account_id, account_name, lifecycle_status, aggregate_version] + required: + - account_id + - account_name + - lifecycle_status + - aggregate_version properties: - account_id: { type: string, format: uuid } - account_name: { type: string, minLength: 1, maxLength: 300 } - lifecycle_status: { type: string, enum: [prospective, active, inactive, closed] } - aggregate_version: { type: integer, minimum: 1 } + account_id: + type: string + format: uuid + account_name: + type: string + minLength: 1 + maxLength: 300 + lifecycle_status: + type: string + enum: + - prospective + - active + - inactive + - closed + aggregate_version: + type: integer + minimum: 1 AccountPage: type: object additionalProperties: false - required: [items, next_cursor, page_size] + required: + - items + - next_cursor + - page_size properties: items: type: array - items: { $ref: '#/components/schemas/Account' } - next_cursor: { type: [string, 'null'] } - page_size: { type: integer, minimum: 1, maximum: 100 } + items: + $ref: '#/components/schemas/Account' + next_cursor: + type: + - string + - 'null' + page_size: + type: integer + minimum: 1 + maximum: 100 CreateAccountRequest: type: object additionalProperties: false - required: [account_name, lifecycle_status] + required: + - account_name + - lifecycle_status properties: - account_name: { type: string, minLength: 1, maxLength: 300 } - lifecycle_status: { type: string, enum: [prospective, active] } + account_name: + type: string + minLength: 1 + maxLength: 300 + lifecycle_status: + type: string + enum: + - prospective + - active UpdateAccountRequest: type: object additionalProperties: false minProperties: 1 properties: - account_name: { type: string, minLength: 1, maxLength: 300 } - lifecycle_status: { type: string, enum: [prospective, active, inactive, closed] } + account_name: + type: string + minLength: 1 + maxLength: 300 + lifecycle_status: + type: string + enum: + - prospective + - active + - inactive + - closed RecordRelationshipRequest: type: object additionalProperties: false - required: [relationship_type_version_id, participants, valid_from, truth_status] + required: + - relationship_type_version_id + - participants + - valid_from + - truth_status properties: - relationship_type_version_id: { type: string, format: uuid } + relationship_type_version_id: + type: string + format: uuid participants: type: array minItems: 2 @@ -222,54 +357,148 @@ components: items: type: object additionalProperties: false - required: [party_id, role_code] + required: + - party_id + - role_code properties: - party_id: { type: string, format: uuid } - role_code: { type: string, pattern: '^[a-z][a-z0-9_]{1,63}$' } - valid_from: { type: string, format: date-time } - valid_to: { type: [string, 'null'], format: date-time } - truth_status: { type: string, enum: [authoritative, observed, inferred, proposed] } + party_id: + type: string + format: uuid + role_code: + type: string + pattern: ^[a-z][a-z0-9_]{1,63}$ + valid_from: + type: string + format: date-time + valid_to: + type: + - string + - 'null' + format: date-time + truth_status: + type: string + enum: + - authoritative + - observed + - inferred + - proposed evidence_reference_ids: type: array maxItems: 100 - items: { type: string, format: uuid } - manual_assertion_reason: { type: [string, 'null'], maxLength: 1000 } + items: + type: string + format: uuid + manual_assertion_reason: + type: + - string + - 'null' + maxLength: 1000 anyOf: - - required: [evidence_reference_ids] - - required: [manual_assertion_reason] + - required: + - evidence_reference_ids + - required: + - manual_assertion_reason StageTransitionRequest: type: object additionalProperties: false - required: [target_stage_definition_id, effective_at, reason_code] + required: + - target_stage_definition_id + - effective_at + - reason_code properties: - target_stage_definition_id: { type: string, format: uuid } - effective_at: { type: string, format: date-time } - reason_code: { type: string, pattern: '^[a-z][a-z0-9_]{1,63}$' } + target_stage_definition_id: + type: string + format: uuid + effective_at: + type: string + format: date-time + reason_code: + type: string + pattern: ^[a-z][a-z0-9_]{1,63}$ evidence_reference_ids: type: array maxItems: 100 - items: { type: string, format: uuid } + items: + type: string + format: uuid OperationReceipt: type: object additionalProperties: false - required: [operation_id, aggregate_reference, aggregate_version, recorded_at, event_reference, idempotency_status] + required: + - operation_id + - aggregate_reference + - aggregate_version + - recorded_at + - event_reference + - idempotency_status properties: - operation_id: { type: string, format: uuid } - aggregate_reference: { type: string, minLength: 8, maxLength: 500 } - aggregate_version: { type: integer, minimum: 1 } - recorded_at: { type: string, format: date-time } - event_reference: { type: string, minLength: 8, maxLength: 500 } - idempotency_status: { type: string, enum: [new, replayed] } + operation_id: + type: string + format: uuid + aggregate_reference: + type: string + minLength: 8 + maxLength: 500 + aggregate_version: + type: integer + minimum: 1 + recorded_at: + type: string + format: date-time + event_reference: + type: string + minLength: 8 + maxLength: 500 + idempotency_status: + type: string + enum: + - new + - replayed Problem: type: object additionalProperties: true - required: [type, title, status, error_code, correlation_id] + required: + - type + - title + - status + - error_code + - correlation_id properties: - type: { type: string, format: uri-reference } - title: { type: string } - status: { type: integer, minimum: 400, maximum: 599 } - detail: { type: string } - instance: { type: string, format: uri-reference } - error_code: { type: string } - correlation_id: { type: string } - safe_next_action: { type: [string, 'null'] } + type: + type: string + format: uri-reference + title: + type: string + status: + type: integer + minimum: 400 + maximum: 599 + detail: + type: string + instance: + type: string + format: uri-reference + error_code: + type: string + correlation_id: + type: string + safe_next_action: + type: + - string + - 'null' + headers: + EffectiveValidAt: + description: Effective business-valid instant applied by the server. + schema: + type: string + format: date-time + EffectiveRecordedAt: + description: Effective system-recorded instant applied by the server. + schema: + type: string + format: date-time + EffectiveKnowledgeCutoff: + description: Effective knowledge cutoff applied by the server. + schema: + type: string + format: date-time From 8dd985766a2beac066e101998205e07e467f78be Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 05:46:10 -0700 Subject: [PATCH 19/87] fix: require event provenance --- schemas/asyncapi.yaml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/schemas/asyncapi.yaml b/schemas/asyncapi.yaml index 664e4e9..8c961f8 100644 --- a/schemas/asyncapi.yaml +++ b/schemas/asyncapi.yaml @@ -68,6 +68,7 @@ components: - datacontenttype - tenantref - correlationid + - provenanceref - purposecode - dataclassification - schemarevision @@ -106,10 +107,10 @@ components: - 'null' maxLength: 128 provenanceref: - type: - - string - - 'null' + type: string + minLength: 8 maxLength: 500 + description: Required reference to the evidence or decision provenance for the event. purposecode: type: string pattern: ^[a-z][a-z0-9_]{1,63}$ From 0601ef88fc1d323326a44d7d4c85ca262091c964 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 05:46:47 -0700 Subject: [PATCH 20/87] ci: verify required event provenance --- .../refresh-provenance-contract-manifest.yml | 125 ++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 .github/workflows/refresh-provenance-contract-manifest.yml diff --git a/.github/workflows/refresh-provenance-contract-manifest.yml b/.github/workflows/refresh-provenance-contract-manifest.yml new file mode 100644 index 0000000..bf47716 --- /dev/null +++ b/.github/workflows/refresh-provenance-contract-manifest.yml @@ -0,0 +1,125 @@ +name: Verify required event provenance + +on: + push: + branches: + - docs/product-technical-baseline + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: elunvera-required-provenance-repair + cancel-in-progress: false + +jobs: + verify-and-refresh: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out exact feature branch + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + ref: docs/product-technical-baseline + fetch-depth: 0 + + - name: Verify required provenance contract + shell: bash + run: | + set -euo pipefail + echo "b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c schemas/asyncapi.yaml" | sha256sum --check - + + ruby -ryaml - <<'RUBY' + contract = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) + raise 'AsyncAPI version mismatch' unless contract['asyncapi'] == '3.1.0' + envelope = contract.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') + required = envelope.fetch('required') + raise 'provenanceref is not required' unless required.include?('provenanceref') + provenance = envelope.fetch('properties').fetch('provenanceref') + raise 'provenanceref must be non-null string' unless provenance['type'] == 'string' + raise 'provenanceref must reject empty references' unless provenance['minLength'].to_i >= 1 + raise 'producer operations regressed' unless contract.fetch('operations').values.all? { |operation| operation['action'] == 'send' } + RUBY + + - name: Regenerate the deterministic manifest + shell: bash + run: | + set -euo pipefail + git rm .github/workflows/refresh-provenance-contract-manifest.yml + python - <<'PY' + import hashlib + import json + import subprocess + from pathlib import Path + + manifest_path = Path('manifest.json') + manifest = json.loads(manifest_path.read_text(encoding='utf-8')) + paths = [ + Path(path) + for path in subprocess.check_output( + ['git', 'ls-files'], text=True + ).splitlines() + if path != 'manifest.json' + ] + entries = [] + for path in sorted(paths, key=lambda item: item.as_posix()): + payload = path.read_bytes() + entries.append( + { + 'path': path.as_posix(), + 'sha256': hashlib.sha256(payload).hexdigest(), + 'size_bytes': len(payload), + 'line_count': len(payload.decode('utf-8').splitlines()), + } + ) + + manifest['file_count'] = len(entries) + manifest['files'] = entries + assert manifest['self_excluded'] is True + assert manifest['file_count'] == 54 + async_entry = next( + entry for entry in entries + if entry['path'] == 'schemas/asyncapi.yaml' + ) + assert async_entry == { + 'path': 'schemas/asyncapi.yaml', + 'sha256': 'b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c', + 'size_bytes': 3682, + 'line_count': 126, + } + manifest_path.write_text( + json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', + encoding='utf-8', + ) + PY + + git add manifest.json + git diff --cached --check + + python - <<'PY' + import hashlib + import json + from pathlib import Path + + manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) + assert manifest['file_count'] == len(manifest['files']) == 54 + for entry in manifest['files']: + path = Path(entry['path']) + payload = path.read_bytes() + assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path + assert len(payload) == entry['size_bytes'], path + assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path + PY + + - name: Commit verified manifest refresh + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + test "$(git ls-files | wc -l)" -eq 55 + test ! -e .github/workflows/refresh-provenance-contract-manifest.yml + git commit -m "chore: refresh required-provenance manifest" + git push origin HEAD:docs/product-technical-baseline From fe5b69cef0ea778cb98853dc211a052151b5040f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 29 Aug 2026 12:47:11 +0000 Subject: [PATCH 21/87] chore: refresh required-provenance manifest --- .../refresh-provenance-contract-manifest.yml | 125 ------------------ manifest.json | 6 +- 2 files changed, 3 insertions(+), 128 deletions(-) delete mode 100644 .github/workflows/refresh-provenance-contract-manifest.yml diff --git a/.github/workflows/refresh-provenance-contract-manifest.yml b/.github/workflows/refresh-provenance-contract-manifest.yml deleted file mode 100644 index bf47716..0000000 --- a/.github/workflows/refresh-provenance-contract-manifest.yml +++ /dev/null @@ -1,125 +0,0 @@ -name: Verify required event provenance - -on: - push: - branches: - - docs/product-technical-baseline - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: elunvera-required-provenance-repair - cancel-in-progress: false - -jobs: - verify-and-refresh: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out exact feature branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - ref: docs/product-technical-baseline - fetch-depth: 0 - - - name: Verify required provenance contract - shell: bash - run: | - set -euo pipefail - echo "b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c schemas/asyncapi.yaml" | sha256sum --check - - - ruby -ryaml - <<'RUBY' - contract = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) - raise 'AsyncAPI version mismatch' unless contract['asyncapi'] == '3.1.0' - envelope = contract.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') - required = envelope.fetch('required') - raise 'provenanceref is not required' unless required.include?('provenanceref') - provenance = envelope.fetch('properties').fetch('provenanceref') - raise 'provenanceref must be non-null string' unless provenance['type'] == 'string' - raise 'provenanceref must reject empty references' unless provenance['minLength'].to_i >= 1 - raise 'producer operations regressed' unless contract.fetch('operations').values.all? { |operation| operation['action'] == 'send' } - RUBY - - - name: Regenerate the deterministic manifest - shell: bash - run: | - set -euo pipefail - git rm .github/workflows/refresh-provenance-contract-manifest.yml - python - <<'PY' - import hashlib - import json - import subprocess - from pathlib import Path - - manifest_path = Path('manifest.json') - manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - paths = [ - Path(path) - for path in subprocess.check_output( - ['git', 'ls-files'], text=True - ).splitlines() - if path != 'manifest.json' - ] - entries = [] - for path in sorted(paths, key=lambda item: item.as_posix()): - payload = path.read_bytes() - entries.append( - { - 'path': path.as_posix(), - 'sha256': hashlib.sha256(payload).hexdigest(), - 'size_bytes': len(payload), - 'line_count': len(payload.decode('utf-8').splitlines()), - } - ) - - manifest['file_count'] = len(entries) - manifest['files'] = entries - assert manifest['self_excluded'] is True - assert manifest['file_count'] == 54 - async_entry = next( - entry for entry in entries - if entry['path'] == 'schemas/asyncapi.yaml' - ) - assert async_entry == { - 'path': 'schemas/asyncapi.yaml', - 'sha256': 'b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c', - 'size_bytes': 3682, - 'line_count': 126, - } - manifest_path.write_text( - json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', - encoding='utf-8', - ) - PY - - git add manifest.json - git diff --cached --check - - python - <<'PY' - import hashlib - import json - from pathlib import Path - - manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) - assert manifest['file_count'] == len(manifest['files']) == 54 - for entry in manifest['files']: - path = Path(entry['path']) - payload = path.read_bytes() - assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path - assert len(payload) == entry['size_bytes'], path - assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path - PY - - - name: Commit verified manifest refresh - shell: bash - run: | - set -euo pipefail - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - test "$(git ls-files | wc -l)" -eq 55 - test ! -e .github/workflows/refresh-provenance-contract-manifest.yml - git commit -m "chore: refresh required-provenance manifest" - git push origin HEAD:docs/product-technical-baseline diff --git a/manifest.json b/manifest.json index 8fbd2b7..2ecc5c3 100644 --- a/manifest.json +++ b/manifest.json @@ -308,9 +308,9 @@ }, { "path": "schemas/asyncapi.yaml", - "sha256": "6114f1df68a25182dd454903a77e8da343f0c343ca51d0162163a87f56c4fb42", - "size_bytes": 3572, - "line_count": 125 + "sha256": "b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c", + "size_bytes": 3682, + "line_count": 126 }, { "path": "schemas/events/opportunity-stage-changed-v1.schema.json", From 14351f1d770da2c43185030b5e5eb8b9ba0f64a3 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 05:48:37 -0700 Subject: [PATCH 22/87] ci: add exact-head document contract validation --- .github/workflows/document-contracts.yml | 160 +++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 .github/workflows/document-contracts.yml diff --git a/.github/workflows/document-contracts.yml b/.github/workflows/document-contracts.yml new file mode 100644 index 0000000..a7d580b --- /dev/null +++ b/.github/workflows/document-contracts.yml @@ -0,0 +1,160 @@ +name: document-contracts + +on: + pull_request: + branches: + - develop + push: + branches: + - develop + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: document-contracts-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + validate: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out exact revision + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + ref: ${{ github.event.pull_request.head.sha || github.sha }} + persist-credentials: false + + - name: Verify exact checkout + env: + EXPECTED_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + run: test "$(git rev-parse HEAD)" = "$EXPECTED_SHA" + + - name: Validate document and schema contracts + shell: bash + run: | + set -euo pipefail + + ruby -ryaml - <<'RUBY' + methods = %w[get post put patch delete options head trace] + openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) + raise 'OpenAPI version mismatch' unless openapi['openapi'] == '3.2.0' + operations = [] + openapi.fetch('paths').each do |path, item| + item.each do |method, operation| + next unless methods.include?(method) + operations << [method.upcase, "/v1#{path}", operation.fetch('operationId')] + end + end + expected = [ + ['GET', '/v1/accounts'], + ['POST', '/v1/accounts'], + ['GET', '/v1/accounts/{account_id}'], + ['PATCH', '/v1/accounts/{account_id}'], + ['POST', '/v1/relationships'], + ['POST', '/v1/opportunities/{opportunity_id}/stage-transitions'] + ].sort + raise 'OpenAPI P0 operation mismatch' unless operations.map { |method, path, _| [method, path] }.sort == expected + raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length + + ['/accounts', '/accounts/{account_id}'].each do |path| + operation = openapi.fetch('paths').fetch(path).fetch('get') + refs = operation.fetch('parameters').filter_map { |parameter| parameter['$ref'] } + %w[ValidAt RecordedAt KnowledgeCutoff].each do |name| + raise "missing temporal parameter #{name}" unless refs.include?("#/components/parameters/#{name}") + end + headers = operation.fetch('responses').fetch('200').fetch('headers') + %w[X-ELUNVERA-Valid-At X-ELUNVERA-Recorded-At X-ELUNVERA-Knowledge-Cutoff].each do |name| + raise "missing temporal response header #{name}" unless headers.key?(name) + end + end + + asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) + raise 'AsyncAPI version mismatch' unless asyncapi['asyncapi'] == '3.1.0' + raise 'event producer direction mismatch' unless asyncapi.fetch('operations').values.all? { |operation| operation['action'] == 'send' } + envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') + %w[dataclassification schemarevision provenanceref].each do |name| + raise "missing required event metadata #{name}" unless envelope.fetch('required').include?(name) + end + provenance = envelope.fetch('properties').fetch('provenanceref') + raise 'provenance must be a non-null string' unless provenance['type'] == 'string' + raise 'provenance must reject empty values' unless provenance['minLength'].to_i >= 1 + RUBY + + python - <<'PY' + import hashlib + import json + import re + import subprocess + from pathlib import Path + from urllib.parse import unquote + + required = { + Path('docs/PRD.md'), + Path('docs/TRD.md'), + Path('docs/ARCHITECTURE.md'), + Path('docs/DATA_MODEL.md'), + Path('docs/API_CONTRACT.md'), + Path('docs/product-technical-gap-baseline.md'), + Path('docs/adr/README.md'), + Path('schemas/openapi.yaml'), + Path('schemas/asyncapi.yaml'), + } + missing = sorted(str(path) for path in required if not path.is_file()) + assert not missing, missing + + for event_path in ( + Path('schemas/events/relationship-changed-v1.schema.json'), + Path('schemas/events/opportunity-stage-changed-v1.schema.json'), + ): + schema = json.loads(event_path.read_text(encoding='utf-8')) + assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema' + assert schema['additionalProperties'] is False + assert 'recorded_at' in schema['required'] + assert schema['properties']['recorded_at']['format'] == 'date-time' + + manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) + tracked = { + path + for path in subprocess.check_output( + ['git', 'ls-files'], text=True + ).splitlines() + if path != 'manifest.json' + } + entries = {entry['path']: entry for entry in manifest['files']} + assert manifest['self_excluded'] is True + assert manifest['file_count'] == len(entries) == len(tracked) + assert set(entries) == tracked + for path_text, entry in entries.items(): + path = Path(path_text) + payload = path.read_bytes() + assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path + assert len(payload) == entry['size_bytes'], path + assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path + + link_pattern = re.compile(r'(?') + if target.startswith(('http://', 'https://', 'mailto:', '#')): + continue + target = unquote(target.split('#', 1)[0]) + if not target: + continue + resolved = (markdown_path.parent / target).resolve() + assert resolved.exists(), f'{markdown_path}:{line_number}: {target}' + assert fence_count % 2 == 0, f'unbalanced code fence: {markdown_path}' + PY + + git diff --check From cbf281d2884f9da22cfac2e3fd2ba12bfb4db852 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 05:50:13 -0700 Subject: [PATCH 23/87] ci: refresh exact-head document manifest --- .../refresh-document-contract-manifest.yml | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 .github/workflows/refresh-document-contract-manifest.yml diff --git a/.github/workflows/refresh-document-contract-manifest.yml b/.github/workflows/refresh-document-contract-manifest.yml new file mode 100644 index 0000000..dba70f5 --- /dev/null +++ b/.github/workflows/refresh-document-contract-manifest.yml @@ -0,0 +1,114 @@ +name: Refresh exact-head document manifest + +on: + push: + branches: + - docs/product-technical-baseline + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: elunvera-document-manifest-refresh + cancel-in-progress: false + +jobs: + refresh: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out exact feature branch + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + ref: docs/product-technical-baseline + fetch-depth: 0 + + - name: Regenerate manifest from the final tracked tree + shell: bash + run: | + set -euo pipefail + test -f .github/workflows/document-contracts.yml + git rm .github/workflows/refresh-document-contract-manifest.yml + + python - <<'PY' + import hashlib + import json + import subprocess + from pathlib import Path + + manifest_path = Path('manifest.json') + manifest = json.loads(manifest_path.read_text(encoding='utf-8')) + paths = [ + Path(path) + for path in subprocess.check_output( + ['git', 'ls-files'], text=True + ).splitlines() + if path != 'manifest.json' + ] + entries = [] + for path in sorted(paths, key=lambda item: item.as_posix()): + payload = path.read_bytes() + entries.append( + { + 'path': path.as_posix(), + 'sha256': hashlib.sha256(payload).hexdigest(), + 'size_bytes': len(payload), + 'line_count': len(payload.decode('utf-8').splitlines()), + } + ) + + manifest['generated_at'] = '2026-08-29T12:50:00Z' + manifest['file_count'] = len(entries) + manifest['files'] = entries + assert manifest['self_excluded'] is True + assert manifest['file_count'] == 55 + paths_in_manifest = {entry['path'] for entry in entries} + assert '.github/workflows/document-contracts.yml' in paths_in_manifest + assert '.github/workflows/refresh-document-contract-manifest.yml' not in paths_in_manifest + assert 'schemas/asyncapi.yaml' in paths_in_manifest + manifest_path.write_text( + json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', + encoding='utf-8', + ) + PY + + git add manifest.json + git diff --cached --check + + python - <<'PY' + import hashlib + import json + import subprocess + from pathlib import Path + + manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) + tracked = { + path + for path in subprocess.check_output( + ['git', 'ls-files'], text=True + ).splitlines() + if path != 'manifest.json' + } + entries = {entry['path']: entry for entry in manifest['files']} + assert manifest['file_count'] == len(entries) == len(tracked) == 55 + assert set(entries) == tracked + for path_text, entry in entries.items(): + path = Path(path_text) + payload = path.read_bytes() + assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path + assert len(payload) == entry['size_bytes'], path + assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path + PY + + - name: Commit verified final manifest + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + test "$(git ls-files | wc -l)" -eq 56 + test ! -e .github/workflows/refresh-document-contract-manifest.yml + git commit -m "chore: refresh exact-head document manifest" + git push origin HEAD:docs/product-technical-baseline From 208f9805449a1b26bc1ae70daf4f5888bb58ff82 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 29 Aug 2026 12:50:20 +0000 Subject: [PATCH 24/87] chore: refresh exact-head document manifest --- .../refresh-document-contract-manifest.yml | 114 ------------------ manifest.json | 10 +- 2 files changed, 8 insertions(+), 116 deletions(-) delete mode 100644 .github/workflows/refresh-document-contract-manifest.yml diff --git a/.github/workflows/refresh-document-contract-manifest.yml b/.github/workflows/refresh-document-contract-manifest.yml deleted file mode 100644 index dba70f5..0000000 --- a/.github/workflows/refresh-document-contract-manifest.yml +++ /dev/null @@ -1,114 +0,0 @@ -name: Refresh exact-head document manifest - -on: - push: - branches: - - docs/product-technical-baseline - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: elunvera-document-manifest-refresh - cancel-in-progress: false - -jobs: - refresh: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out exact feature branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - ref: docs/product-technical-baseline - fetch-depth: 0 - - - name: Regenerate manifest from the final tracked tree - shell: bash - run: | - set -euo pipefail - test -f .github/workflows/document-contracts.yml - git rm .github/workflows/refresh-document-contract-manifest.yml - - python - <<'PY' - import hashlib - import json - import subprocess - from pathlib import Path - - manifest_path = Path('manifest.json') - manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - paths = [ - Path(path) - for path in subprocess.check_output( - ['git', 'ls-files'], text=True - ).splitlines() - if path != 'manifest.json' - ] - entries = [] - for path in sorted(paths, key=lambda item: item.as_posix()): - payload = path.read_bytes() - entries.append( - { - 'path': path.as_posix(), - 'sha256': hashlib.sha256(payload).hexdigest(), - 'size_bytes': len(payload), - 'line_count': len(payload.decode('utf-8').splitlines()), - } - ) - - manifest['generated_at'] = '2026-08-29T12:50:00Z' - manifest['file_count'] = len(entries) - manifest['files'] = entries - assert manifest['self_excluded'] is True - assert manifest['file_count'] == 55 - paths_in_manifest = {entry['path'] for entry in entries} - assert '.github/workflows/document-contracts.yml' in paths_in_manifest - assert '.github/workflows/refresh-document-contract-manifest.yml' not in paths_in_manifest - assert 'schemas/asyncapi.yaml' in paths_in_manifest - manifest_path.write_text( - json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', - encoding='utf-8', - ) - PY - - git add manifest.json - git diff --cached --check - - python - <<'PY' - import hashlib - import json - import subprocess - from pathlib import Path - - manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) - tracked = { - path - for path in subprocess.check_output( - ['git', 'ls-files'], text=True - ).splitlines() - if path != 'manifest.json' - } - entries = {entry['path']: entry for entry in manifest['files']} - assert manifest['file_count'] == len(entries) == len(tracked) == 55 - assert set(entries) == tracked - for path_text, entry in entries.items(): - path = Path(path_text) - payload = path.read_bytes() - assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path - assert len(payload) == entry['size_bytes'], path - assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path - PY - - - name: Commit verified final manifest - shell: bash - run: | - set -euo pipefail - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - test "$(git ls-files | wc -l)" -eq 56 - test ! -e .github/workflows/refresh-document-contract-manifest.yml - git commit -m "chore: refresh exact-head document manifest" - git push origin HEAD:docs/product-technical-baseline diff --git a/manifest.json b/manifest.json index 2ecc5c3..97c7637 100644 --- a/manifest.json +++ b/manifest.json @@ -1,10 +1,10 @@ { "schema_version": "1.0", "product": "ELUNVERA", - "generated_at": "2026-08-29T00:00:00Z", + "generated_at": "2026-08-29T12:50:00Z", "algorithm": "SHA-256", "self_excluded": true, - "file_count": 54, + "file_count": 55, "files": [ { "path": ".cwl/data-management.yaml", @@ -18,6 +18,12 @@ "size_bytes": 1064, "line_count": 38 }, + { + "path": ".github/workflows/document-contracts.yml", + "sha256": "4753940663837d4326b3954a300545738ec5a16ef72bd9e6cfcadc6ab2ea00f1", + "size_bytes": 7127, + "line_count": 160 + }, { "path": "AGENTS.md", "sha256": "8d308fc7f687ad53e18aabc95cbb175a48450b8bfe502b29562f0afd9c950d13", From bc7e86c4f2e6c01479191575beb3a4ad8d9687cf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 05:51:19 -0700 Subject: [PATCH 25/87] ci: trigger exact-head document contract validation From b0dcb301c8fc71add7959e2926842c30a465c738 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 06:02:23 -0700 Subject: [PATCH 26/87] ci: repair remaining contract review findings --- .github/workflows/repair-review-round-3.yml | 183 ++++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 .github/workflows/repair-review-round-3.yml diff --git a/.github/workflows/repair-review-round-3.yml b/.github/workflows/repair-review-round-3.yml new file mode 100644 index 0000000..e62e645 --- /dev/null +++ b/.github/workflows/repair-review-round-3.yml @@ -0,0 +1,183 @@ +name: repair remaining contract review findings + +on: + push: + branches: + - docs/product-technical-baseline + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: elunvera-review-round-3-repair + cancel-in-progress: false + +jobs: + repair: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out exact feature branch + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + ref: docs/product-technical-baseline + fetch-depth: 0 + + - name: Verify bounded preimage + shell: bash + env: + EXPECTED_PARENT: bc7e86c4f2e6c01479191575beb3a4ad8d9687cf + run: | + set -euo pipefail + test "$(git rev-parse HEAD^)" = "$EXPECTED_PARENT" + + - name: Apply review repairs and refresh durable evidence + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + import hashlib + import json + from pathlib import Path + + openapi_path = Path('schemas/openapi.yaml') + openapi = openapi_path.read_text(encoding='utf-8') + start = openapi.index(' RecordRelationshipRequest:\n') + end = openapi.index(' StageTransitionRequest:\n') + prefix, relationship, suffix = openapi[:start], openapi[start:end], openapi[end:] + inferred = ' - inferred\n' + assert relationship.count(inferred) == 1 + relationship = relationship.replace(inferred, '') + evidence = ''' evidence_reference_ids: + type: array + maxItems: 100 +''' + bounded_evidence = ''' evidence_reference_ids: + type: array + minItems: 1 + maxItems: 100 +''' + assert relationship.count(evidence) == 1 + relationship = relationship.replace(evidence, bounded_evidence) + openapi_path.write_text(prefix + relationship + suffix, encoding='utf-8') + + validation_path = Path('docs/VALIDATION_REPORT.md') + validation = validation_path.read_text(encoding='utf-8') + replacements = { + '- **Validation date:** 2026-08-27': '- **Validation date:** 2026-08-29', + '| JSON Schema Draft 2020-12 metaschema validation | Pass |': '| JSON Schema Draft 2020-12 declaration and structural invariant validation | Pass |', + '- Repository files excluding `.git`: **55**': '- Tracked repository files including `manifest.json`: **56**', + '- Manifest entries excluding `manifest.json`: **54**': '- Manifest entries excluding `manifest.json`: **55**', + 'Python JSON and JSON Schema validation': 'Python JSON parsing and Draft 2020-12 declaration/invariant validation', + } + for old, new in replacements.items(): + assert old in validation, old + validation = validation.replace(old, new, 1) + validation_path.write_text(validation, encoding='utf-8') + + changelog_path = Path('CHANGELOG.md') + changelog = changelog_path.read_text(encoding='utf-8') + marker = '- Added explicit `recorded_at` payload fields so outbox publication delay cannot corrupt bitemporal reconstruction.\n' + additions = marker + '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.\n- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.\n' + assert changelog.count(marker) == 1 + changelog_path.write_text(changelog.replace(marker, additions, 1), encoding='utf-8') + + workflow_path = Path('.github/workflows/document-contracts.yml') + workflow = workflow_path.read_text(encoding='utf-8') + ruby_marker = " raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length\n\n" + ruby_addition = ruby_marker + ''' relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') + truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') + raise 'P0 manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred') + evidence = relationship.fetch('properties').fetch('evidence_reference_ids') + raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1 + +''' + assert workflow.count(ruby_marker) == 1 + workflow = workflow.replace(ruby_marker, ruby_addition, 1) + python_marker = " assert set(entries) == tracked\n" + python_addition = python_marker + ''' + report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') + assert '- Tracked repository files including `manifest.json`: **56**' in report + assert '- Manifest entries excluding `manifest.json`: **55**' in report + assert 'Draft 2020-12 declaration and structural invariant validation' in report +''' + assert workflow.count(python_marker) == 1 + workflow_path.write_text(workflow.replace(python_marker, python_addition, 1), encoding='utf-8') + + Path('.github/workflows/repair-review-round-3.yml').unlink() + + manifest_path = Path('manifest.json') + manifest = json.loads(manifest_path.read_text(encoding='utf-8')) + tracked = [] + for path in sorted(Path('.').rglob('*')): + if not path.is_file() or '.git' in path.parts or path == manifest_path: + continue + payload = path.read_bytes() + tracked.append({ + 'path': path.as_posix(), + 'sha256': hashlib.sha256(payload).hexdigest(), + 'size_bytes': len(payload), + 'line_count': len(payload.decode('utf-8').splitlines()), + }) + manifest['generated_at'] = '2026-08-29T00:00:00Z' + manifest['file_count'] = len(tracked) + manifest['files'] = tracked + assert len(tracked) == 55 + manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') + PY + + - name: Validate repaired exact tree + shell: bash + run: | + set -euo pipefail + ruby -ryaml - <<'RUBY' + openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) + relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') + truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') + raise 'inferred truth remains accepted' if truth_statuses.include?('inferred') + evidence = relationship.fetch('properties').fetch('evidence_reference_ids') + raise 'empty evidence array remains accepted' unless evidence.fetch('minItems').to_i >= 1 + YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false) + RUBY + + python3 <<'PY' + import hashlib + import json + import subprocess + from pathlib import Path + + report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') + assert '- Tracked repository files including `manifest.json`: **56**' in report + assert '- Manifest entries excluding `manifest.json`: **55**' in report + assert 'Draft 2020-12 declaration and structural invariant validation' in report + assert 'metaschema validation' not in report + + manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) + files = [path for path in Path('.').rglob('*') if path.is_file() and '.git' not in path.parts] + assert len(files) == 56 + entries = {entry['path']: entry for entry in manifest['files']} + assert manifest['file_count'] == len(entries) == 55 + for path_text, entry in entries.items(): + payload = Path(path_text).read_bytes() + assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text + assert len(payload) == entry['size_bytes'], path_text + assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text + for event_path in Path('schemas/events').glob('*.json'): + schema = json.loads(event_path.read_text(encoding='utf-8')) + assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema' + assert schema['additionalProperties'] is False + PY + git diff --check + + - name: Commit verified review repairs + shell: bash + run: | + set -euo pipefail + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + git commit -m "fix: close remaining contract review findings" + git push origin HEAD:docs/product-technical-baseline From 41b7dd497b21e3a7777fdef51cecd3816c6fb5d4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 06:05:55 -0700 Subject: [PATCH 27/87] ci: fix bounded review repair workflow --- .github/workflows/repair-review-round-3.yml | 55 ++++++++++----------- 1 file changed, 25 insertions(+), 30 deletions(-) diff --git a/.github/workflows/repair-review-round-3.yml b/.github/workflows/repair-review-round-3.yml index e62e645..4c6f0a6 100644 --- a/.github/workflows/repair-review-round-3.yml +++ b/.github/workflows/repair-review-round-3.yml @@ -27,11 +27,10 @@ jobs: - name: Verify bounded preimage shell: bash - env: - EXPECTED_PARENT: bc7e86c4f2e6c01479191575beb3a4ad8d9687cf run: | set -euo pipefail - test "$(git rev-parse HEAD^)" = "$EXPECTED_PARENT" + test "$(git rev-parse HEAD^)" = "b0dcb301c8fc71add7959e2926842c30a465c738" + test "$(git rev-parse HEAD^^)" = "bc7e86c4f2e6c01479191575beb3a4ad8d9687cf" - name: Apply review repairs and refresh durable evidence shell: bash @@ -50,15 +49,8 @@ jobs: inferred = ' - inferred\n' assert relationship.count(inferred) == 1 relationship = relationship.replace(inferred, '') - evidence = ''' evidence_reference_ids: - type: array - maxItems: 100 -''' - bounded_evidence = ''' evidence_reference_ids: - type: array - minItems: 1 - maxItems: 100 -''' + evidence = ' evidence_reference_ids:\n type: array\n maxItems: 100\n' + bounded_evidence = ' evidence_reference_ids:\n type: array\n minItems: 1\n maxItems: 100\n' assert relationship.count(evidence) == 1 relationship = relationship.replace(evidence, bounded_evidence) openapi_path.write_text(prefix + relationship + suffix, encoding='utf-8') @@ -80,31 +72,35 @@ jobs: changelog_path = Path('CHANGELOG.md') changelog = changelog_path.read_text(encoding='utf-8') marker = '- Added explicit `recorded_at` payload fields so outbox publication delay cannot corrupt bitemporal reconstruction.\n' - additions = marker + '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.\n- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.\n' + extra = ( + '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.\n' + '- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.\n' + ) assert changelog.count(marker) == 1 - changelog_path.write_text(changelog.replace(marker, additions, 1), encoding='utf-8') + changelog_path.write_text(changelog.replace(marker, marker + extra, 1), encoding='utf-8') workflow_path = Path('.github/workflows/document-contracts.yml') workflow = workflow_path.read_text(encoding='utf-8') ruby_marker = " raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length\n\n" - ruby_addition = ruby_marker + ''' relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') - truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') - raise 'P0 manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred') - evidence = relationship.fetch('properties').fetch('evidence_reference_ids') - raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1 - -''' + ruby_lines = [ + " relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest')\n", + " truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum')\n", + " raise 'P0 manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred')\n", + " evidence = relationship.fetch('properties').fetch('evidence_reference_ids')\n", + " raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1\n\n", + ] assert workflow.count(ruby_marker) == 1 - workflow = workflow.replace(ruby_marker, ruby_addition, 1) + workflow = workflow.replace(ruby_marker, ruby_marker + ''.join(ruby_lines), 1) python_marker = " assert set(entries) == tracked\n" - python_addition = python_marker + ''' - report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') - assert '- Tracked repository files including `manifest.json`: **56**' in report - assert '- Manifest entries excluding `manifest.json`: **55**' in report - assert 'Draft 2020-12 declaration and structural invariant validation' in report -''' + python_lines = [ + "\n", + " report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8')\n", + " assert '- Tracked repository files including `manifest.json`: **56**' in report\n", + " assert '- Manifest entries excluding `manifest.json`: **55**' in report\n", + " assert 'Draft 2020-12 declaration and structural invariant validation' in report\n", + ] assert workflow.count(python_marker) == 1 - workflow_path.write_text(workflow.replace(python_marker, python_addition, 1), encoding='utf-8') + workflow_path.write_text(workflow.replace(python_marker, python_marker + ''.join(python_lines), 1), encoding='utf-8') Path('.github/workflows/repair-review-round-3.yml').unlink() @@ -145,7 +141,6 @@ jobs: python3 <<'PY' import hashlib import json - import subprocess from pathlib import Path report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') From 538e563fd0f3cce1f24d6f5941bb89667f4a1344 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 06:08:14 -0700 Subject: [PATCH 28/87] ci: surface and commit bounded review repairs --- .github/workflows/repair-review-round-3.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/repair-review-round-3.yml b/.github/workflows/repair-review-round-3.yml index 4c6f0a6..69e71c3 100644 --- a/.github/workflows/repair-review-round-3.yml +++ b/.github/workflows/repair-review-round-3.yml @@ -29,8 +29,8 @@ jobs: shell: bash run: | set -euo pipefail - test "$(git rev-parse HEAD^)" = "b0dcb301c8fc71add7959e2926842c30a465c738" - test "$(git rev-parse HEAD^^)" = "bc7e86c4f2e6c01479191575beb3a4ad8d9687cf" + test "$(git rev-parse HEAD^)" = "41b7dd497b21e3a7777fdef51cecd3816c6fb5d4" + test "$(git rev-parse HEAD^^)" = "b0dcb301c8fc71add7959e2926842c30a465c738" - name: Apply review repairs and refresh durable evidence shell: bash @@ -172,7 +172,10 @@ jobs: set -euo pipefail git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git status --short git add -A - git diff --cached --check + git status --short + git diff --cached --stat + test -n "$(git diff --cached --name-only)" git commit -m "fix: close remaining contract review findings" git push origin HEAD:docs/product-technical-baseline From a71a5da2017babf8a9e14c1dd5a8968c1a219ea4 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 06:12:44 -0700 Subject: [PATCH 29/87] ci: make review repair atomic --- .github/workflows/repair-review-round-3.yml | 87 +++++++++------------ 1 file changed, 37 insertions(+), 50 deletions(-) diff --git a/.github/workflows/repair-review-round-3.yml b/.github/workflows/repair-review-round-3.yml index 69e71c3..1042284 100644 --- a/.github/workflows/repair-review-round-3.yml +++ b/.github/workflows/repair-review-round-3.yml @@ -25,17 +25,12 @@ jobs: ref: docs/product-technical-baseline fetch-depth: 0 - - name: Verify bounded preimage + - name: Repair, validate, commit, and push atomically shell: bash run: | set -euo pipefail - test "$(git rev-parse HEAD^)" = "41b7dd497b21e3a7777fdef51cecd3816c6fb5d4" - test "$(git rev-parse HEAD^^)" = "b0dcb301c8fc71add7959e2926842c30a465c738" + test "$(git rev-parse HEAD^)" = "538e563fd0f3cce1f24d6f5941bb89667f4a1344" - - name: Apply review repairs and refresh durable evidence - shell: bash - run: | - set -euo pipefail python3 <<'PY' import hashlib import json @@ -46,9 +41,11 @@ jobs: start = openapi.index(' RecordRelationshipRequest:\n') end = openapi.index(' StageTransitionRequest:\n') prefix, relationship, suffix = openapi[:start], openapi[start:end], openapi[end:] + inferred = ' - inferred\n' assert relationship.count(inferred) == 1 relationship = relationship.replace(inferred, '') + evidence = ' evidence_reference_ids:\n type: array\n maxItems: 100\n' bounded_evidence = ' evidence_reference_ids:\n type: array\n minItems: 1\n maxItems: 100\n' assert relationship.count(evidence) == 1 @@ -65,7 +62,7 @@ jobs: 'Python JSON and JSON Schema validation': 'Python JSON parsing and Draft 2020-12 declaration/invariant validation', } for old, new in replacements.items(): - assert old in validation, old + assert validation.count(old) == 1, old validation = validation.replace(old, new, 1) validation_path.write_text(validation, encoding='utf-8') @@ -79,55 +76,55 @@ jobs: assert changelog.count(marker) == 1 changelog_path.write_text(changelog.replace(marker, marker + extra, 1), encoding='utf-8') - workflow_path = Path('.github/workflows/document-contracts.yml') - workflow = workflow_path.read_text(encoding='utf-8') + permanent_workflow_path = Path('.github/workflows/document-contracts.yml') + permanent_workflow = permanent_workflow_path.read_text(encoding='utf-8') ruby_marker = " raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length\n\n" - ruby_lines = [ - " relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest')\n", - " truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum')\n", - " raise 'P0 manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred')\n", - " evidence = relationship.fetch('properties').fetch('evidence_reference_ids')\n", - " raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1\n\n", - ] - assert workflow.count(ruby_marker) == 1 - workflow = workflow.replace(ruby_marker, ruby_marker + ''.join(ruby_lines), 1) + ruby_checks = ( + " relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest')\n" + " truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum')\n" + " raise 'P0 manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred')\n" + " evidence = relationship.fetch('properties').fetch('evidence_reference_ids')\n" + " raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1\n\n" + ) + assert permanent_workflow.count(ruby_marker) == 1 + permanent_workflow = permanent_workflow.replace(ruby_marker, ruby_marker + ruby_checks, 1) + python_marker = " assert set(entries) == tracked\n" - python_lines = [ - "\n", - " report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8')\n", - " assert '- Tracked repository files including `manifest.json`: **56**' in report\n", - " assert '- Manifest entries excluding `manifest.json`: **55**' in report\n", - " assert 'Draft 2020-12 declaration and structural invariant validation' in report\n", - ] - assert workflow.count(python_marker) == 1 - workflow_path.write_text(workflow.replace(python_marker, python_marker + ''.join(python_lines), 1), encoding='utf-8') + python_checks = ( + "\n" + " report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8')\n" + " assert '- Tracked repository files including `manifest.json`: **56**' in report\n" + " assert '- Manifest entries excluding `manifest.json`: **55**' in report\n" + " assert 'Draft 2020-12 declaration and structural invariant validation' in report\n" + ) + assert permanent_workflow.count(python_marker) == 1 + permanent_workflow_path.write_text( + permanent_workflow.replace(python_marker, python_marker + python_checks, 1), + encoding='utf-8', + ) Path('.github/workflows/repair-review-round-3.yml').unlink() manifest_path = Path('manifest.json') manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - tracked = [] + entries = [] for path in sorted(Path('.').rglob('*')): if not path.is_file() or '.git' in path.parts or path == manifest_path: continue payload = path.read_bytes() - tracked.append({ + entries.append({ 'path': path.as_posix(), 'sha256': hashlib.sha256(payload).hexdigest(), 'size_bytes': len(payload), 'line_count': len(payload.decode('utf-8').splitlines()), }) + assert len(entries) == 55 manifest['generated_at'] = '2026-08-29T00:00:00Z' - manifest['file_count'] = len(tracked) - manifest['files'] = tracked - assert len(tracked) == 55 + manifest['file_count'] = len(entries) + manifest['files'] = entries manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') PY - - name: Validate repaired exact tree - shell: bash - run: | - set -euo pipefail ruby -ryaml - <<'RUBY' openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') @@ -149,9 +146,9 @@ jobs: assert 'Draft 2020-12 declaration and structural invariant validation' in report assert 'metaschema validation' not in report - manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) files = [path for path in Path('.').rglob('*') if path.is_file() and '.git' not in path.parts] assert len(files) == 56 + manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) entries = {entry['path']: entry for entry in manifest['files']} assert manifest['file_count'] == len(entries) == 55 for path_text, entry in entries.items(): @@ -159,23 +156,13 @@ jobs: assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text assert len(payload) == entry['size_bytes'], path_text assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text - for event_path in Path('schemas/events').glob('*.json'): - schema = json.loads(event_path.read_text(encoding='utf-8')) - assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema' - assert schema['additionalProperties'] is False PY - git diff --check - - name: Commit verified review repairs - shell: bash - run: | - set -euo pipefail + git diff --check git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git status --short git add -A - git status --short - git diff --cached --stat + git diff --cached --check test -n "$(git diff --cached --name-only)" git commit -m "fix: close remaining contract review findings" git push origin HEAD:docs/product-technical-baseline From d0ce17eca070766a9bddee39114d497bb3883d03 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 06:16:59 -0700 Subject: [PATCH 30/87] ci: launch independent atomic review repair --- .github/workflows/repair-review-round-4.yml | 159 ++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 .github/workflows/repair-review-round-4.yml diff --git a/.github/workflows/repair-review-round-4.yml b/.github/workflows/repair-review-round-4.yml new file mode 100644 index 0000000..91ad1b0 --- /dev/null +++ b/.github/workflows/repair-review-round-4.yml @@ -0,0 +1,159 @@ +name: atomic ELUNVERA contract review repair + +on: + push: + branches: + - docs/product-technical-baseline + workflow_dispatch: + +permissions: + contents: write + +jobs: + repair: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out exact feature branch + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + ref: docs/product-technical-baseline + fetch-depth: 0 + + - name: Repair, validate, commit, and push in one process + shell: bash + run: | + set -euo pipefail + test "$(git rev-parse HEAD^)" = "a71a5da2017babf8a9e14c1dd5a8968c1a219ea4" + + python3 <<'PY' + import hashlib + import json + from pathlib import Path + + openapi_path = Path('schemas/openapi.yaml') + openapi = openapi_path.read_text(encoding='utf-8') + start = openapi.index(' RecordRelationshipRequest:\n') + end = openapi.index(' StageTransitionRequest:\n') + prefix, relationship, suffix = openapi[:start], openapi[start:end], openapi[end:] + inferred = ' - inferred\n' + assert relationship.count(inferred) == 1 + relationship = relationship.replace(inferred, '') + evidence = ' evidence_reference_ids:\n type: array\n maxItems: 100\n' + bounded_evidence = ' evidence_reference_ids:\n type: array\n minItems: 1\n maxItems: 100\n' + assert relationship.count(evidence) == 1 + relationship = relationship.replace(evidence, bounded_evidence) + openapi_path.write_text(prefix + relationship + suffix, encoding='utf-8') + + validation_path = Path('docs/VALIDATION_REPORT.md') + validation = validation_path.read_text(encoding='utf-8') + replacements = { + '- **Validation date:** 2026-08-27': '- **Validation date:** 2026-08-29', + '| JSON Schema Draft 2020-12 metaschema validation | Pass |': '| JSON Schema Draft 2020-12 declaration and structural invariant validation | Pass |', + '- Repository files excluding `.git`: **55**': '- Tracked repository files including `manifest.json`: **56**', + '- Manifest entries excluding `manifest.json`: **54**': '- Manifest entries excluding `manifest.json`: **55**', + 'Python JSON and JSON Schema validation': 'Python JSON parsing and Draft 2020-12 declaration/invariant validation', + } + for old, new in replacements.items(): + assert validation.count(old) == 1, old + validation = validation.replace(old, new, 1) + validation_path.write_text(validation, encoding='utf-8') + + changelog_path = Path('CHANGELOG.md') + changelog = changelog_path.read_text(encoding='utf-8') + marker = '- Added explicit `recorded_at` payload fields so outbox publication delay cannot corrupt bitemporal reconstruction.\n' + extra = ( + '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.\n' + '- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.\n' + ) + assert changelog.count(marker) == 1 + changelog_path.write_text(changelog.replace(marker, marker + extra, 1), encoding='utf-8') + + permanent_path = Path('.github/workflows/document-contracts.yml') + permanent = permanent_path.read_text(encoding='utf-8') + ruby_marker = " raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length\n\n" + ruby_checks = ( + " relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest')\n" + " truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum')\n" + " raise 'P0 manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred')\n" + " evidence = relationship.fetch('properties').fetch('evidence_reference_ids')\n" + " raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1\n\n" + ) + assert permanent.count(ruby_marker) == 1 + permanent = permanent.replace(ruby_marker, ruby_marker + ruby_checks, 1) + python_marker = " assert set(entries) == tracked\n" + python_checks = ( + "\n" + " report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8')\n" + " assert '- Tracked repository files including `manifest.json`: **56**' in report\n" + " assert '- Manifest entries excluding `manifest.json`: **55**' in report\n" + " assert 'Draft 2020-12 declaration and structural invariant validation' in report\n" + ) + assert permanent.count(python_marker) == 1 + permanent_path.write_text(permanent.replace(python_marker, python_marker + python_checks, 1), encoding='utf-8') + + for temporary in ( + Path('.github/workflows/repair-review-round-3.yml'), + Path('.github/workflows/repair-review-round-4.yml'), + ): + if temporary.exists(): + temporary.unlink() + + manifest_path = Path('manifest.json') + manifest = json.loads(manifest_path.read_text(encoding='utf-8')) + entries = [] + for path in sorted(Path('.').rglob('*')): + if not path.is_file() or '.git' in path.parts or path == manifest_path: + continue + payload = path.read_bytes() + entries.append({ + 'path': path.as_posix(), + 'sha256': hashlib.sha256(payload).hexdigest(), + 'size_bytes': len(payload), + 'line_count': len(payload.decode('utf-8').splitlines()), + }) + assert len(entries) == 55 + manifest['generated_at'] = '2026-08-29T00:00:00Z' + manifest['file_count'] = len(entries) + manifest['files'] = entries + manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') + PY + + ruby -ryaml - <<'RUBY' + openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) + relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') + raise 'inferred truth remains accepted' if relationship.fetch('properties').fetch('truth_status').fetch('enum').include?('inferred') + raise 'empty evidence array remains accepted' unless relationship.fetch('properties').fetch('evidence_reference_ids').fetch('minItems').to_i >= 1 + YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false) + RUBY + + python3 <<'PY' + import hashlib + import json + from pathlib import Path + report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') + assert '- Tracked repository files including `manifest.json`: **56**' in report + assert '- Manifest entries excluding `manifest.json`: **55**' in report + assert 'Draft 2020-12 declaration and structural invariant validation' in report + assert 'metaschema validation' not in report + files = [path for path in Path('.').rglob('*') if path.is_file() and '.git' not in path.parts] + assert len(files) == 56 + manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) + entries = {entry['path']: entry for entry in manifest['files']} + assert manifest['file_count'] == len(entries) == 55 + for path_text, entry in entries.items(): + payload = Path(path_text).read_bytes() + assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text + assert len(payload) == entry['size_bytes'], path_text + assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text + PY + + git diff --check + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + test -n "$(git diff --cached --name-only)" + git commit -m "fix: close remaining contract review findings" + git push origin HEAD:docs/product-technical-baseline From 44d7885098dbec24a476df266760d92c7c98c293 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 06:24:19 -0700 Subject: [PATCH 31/87] ci: stage deterministic contract review repair --- tools/repair_contract_review_round5.py | 323 +++++++++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 tools/repair_contract_review_round5.py diff --git a/tools/repair_contract_review_round5.py b/tools/repair_contract_review_round5.py new file mode 100644 index 0000000..1e5afbf --- /dev/null +++ b/tools/repair_contract_review_round5.py @@ -0,0 +1,323 @@ +"""Apply the final reviewed ELUNVERA contract corrections and remove this repair path. + +This file is intentionally one-shot. The workflow that invokes it removes both +this script and every temporary repair workflow before the resulting commit is +created, so the durable branch contains only product documentation, contracts, +and their permanent exact-head validation workflow. +""" + +from __future__ import annotations + +import hashlib +import json +import re +from pathlib import Path + +ROOT = Path(".") +OPENAPI_PATH = ROOT / "schemas/openapi.yaml" +VALIDATION_PATH = ROOT / "docs/VALIDATION_REPORT.md" +CHANGELOG_PATH = ROOT / "CHANGELOG.md" +PERMANENT_WORKFLOW_PATH = ROOT / ".github/workflows/document-contracts.yml" +MANIFEST_PATH = ROOT / "manifest.json" + +PERMANENT_WORKFLOW = r"""name: document and contract checks + +on: + pull_request: + branches: + - develop + push: + branches: + - develop + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: elunvera-document-contracts-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + validate: + name: validate documentation and contracts + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out exact revision + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Reject temporary repair artifacts + shell: bash + run: | + set -euo pipefail + test ! -e .github/workflows/repair-review-round-3.yml + test ! -e .github/workflows/repair-review-round-4.yml + test ! -e .github/workflows/repair-review-round-5.yml + test ! -e tools/repair_contract_review_round5.py + + - name: Parse and validate YAML contracts + shell: bash + run: | + set -euo pipefail + ruby -ryaml - <<'RUBY' + openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) + raise 'OpenAPI version mismatch' unless openapi.fetch('openapi') == '3.2.0' + + operations = [] + openapi.fetch('paths').each do |path, item| + item.each do |method, operation| + next unless %w[get post put patch delete head options trace].include?(method) + operations << [path, operation.fetch('operationId')] + end + end + raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length + + parameters = openapi.fetch('components').fetch('parameters') + %w[ValidAt RecordedAt KnowledgeCutoff].each do |name| + raise "missing temporal parameter #{name}" unless parameters.key?(name) + end + + relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') + truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') + raise 'P0 manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred') + evidence = relationship.fetch('properties').fetch('evidence_reference_ids') + raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1 + + asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) + raise 'AsyncAPI version mismatch' unless asyncapi.fetch('asyncapi') == '3.1.0' + asyncapi.fetch('operations').each do |name, operation| + raise "#{name} must describe ELUNVERA as producer" unless operation.fetch('action') == 'send' + end + envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') + required = envelope.fetch('required') + raise 'provenance extension must be required' unless required.include?('provenanceref') + raise 'classification extension must be required' unless required.any? { |field| %w[dataclassification data_classification].include?(field) } + raise 'schema revision extension must be required' unless required.any? { |field| %w[schemarevision schema_revision].include?(field) } + RUBY + + - name: Validate manifest, JSON schemas, and durable evidence + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + import hashlib + import json + import re + import subprocess + from pathlib import Path + + manifest_path = Path('manifest.json') + manifest = json.loads(manifest_path.read_text(encoding='utf-8')) + entries = {entry['path']: entry for entry in manifest['files']} + tracked = set(subprocess.check_output(['git', 'ls-files'], text=True).splitlines()) + tracked_without_manifest = tracked - {'manifest.json'} + + assert len(tracked) == 56, len(tracked) + assert manifest['file_count'] == len(entries) == 55 + assert set(entries) == tracked_without_manifest + for path_text, entry in entries.items(): + payload = Path(path_text).read_bytes() + assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text + assert len(payload) == entry['size_bytes'], path_text + assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text + + for event_path in sorted(Path('schemas/events').glob('*.json')): + schema = json.loads(event_path.read_text(encoding='utf-8')) + assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema' + assert schema['additionalProperties'] is False + relationship_event = json.loads(Path('schemas/events/relationship-changed-v1.schema.json').read_text(encoding='utf-8')) + assert 'recorded_at' in relationship_event['required'] + + report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') + assert '- Tracked repository files including `manifest.json`: **56**' in report + assert '- Manifest entries excluding `manifest.json`: **55**' in report + assert 'Draft 2020-12 declaration and structural invariant validation' in report + assert 'metaschema validation' not in report.lower() + + placeholder = re.compile(r'\b(?:TBD|TODO|FIXME)\b') + for path in tracked_without_manifest: + if path.endswith(('.md', '.yaml', '.yml', '.json')): + text = Path(path).read_text(encoding='utf-8') + assert not placeholder.search(text), path + PY + + - name: Validate Markdown links and fences + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + import re + from pathlib import Path + + link_pattern = re.compile(r'(?') + if not target or target.startswith(('#', 'http://', 'https://', 'mailto:')): + continue + local = target.split('#', 1)[0] + if local: + assert (path.parent / local).resolve().exists(), f'broken link: {path} -> {target}' + PY + + - name: Reject whitespace errors + shell: bash + run: git diff --check HEAD^ +""" + + +def repair_openapi() -> None: + text = OPENAPI_PATH.read_text(encoding="utf-8") + start = text.index(" RecordRelationshipRequest:\n") + end = text.index(" StageTransitionRequest:\n", start) + block = text[start:end] + + block = re.sub(r"(?m)^ - inferred\n", "", block) + evidence_header = " evidence_reference_ids:\n type: array\n" + if " evidence_reference_ids:\n type: array\n minItems:" not in block: + if evidence_header not in block: + raise RuntimeError("RecordRelationshipRequest evidence array not found") + block = block.replace(evidence_header, evidence_header + " minItems: 1\n", 1) + + if " - inferred\n" in block: + raise RuntimeError("inferred truth remains in the P0 manual relationship command") + if " minItems: 1\n" not in block: + raise RuntimeError("relationship evidence arrays still accept empty input") + + OPENAPI_PATH.write_text(text[:start] + block + text[end:], encoding="utf-8") + + +def repair_validation_report() -> None: + text = VALIDATION_PATH.read_text(encoding="utf-8") + text = re.sub(r"- \*\*Validation date:\*\* \d{4}-\d{2}-\d{2}", "- **Validation date:** 2026-08-29", text, count=1) + text = text.replace( + "JSON Schema Draft 2020-12 metaschema validation", + "JSON Schema Draft 2020-12 declaration and structural invariant validation", + ) + text = text.replace( + "Python JSON and JSON Schema validation", + "Python JSON parsing and Draft 2020-12 declaration/invariant validation", + ) + text = re.sub( + r"- Repository files excluding `\.git`: \*\*\d+\*\*", + "- Tracked repository files including `manifest.json`: **56**", + text, + ) + text = re.sub( + r"- Manifest entries excluding `manifest\.json`: \*\*\d+\*\*", + "- Manifest entries excluding `manifest.json`: **55**", + text, + ) + if "metaschema validation" in text.lower(): + raise RuntimeError("validation report still overstates metaschema validation") + required = ( + "- Tracked repository files including `manifest.json`: **56**", + "- Manifest entries excluding `manifest.json`: **55**", + "Draft 2020-12 declaration and structural invariant validation", + ) + for value in required: + if value not in text: + raise RuntimeError(f"validation report repair missing: {value}") + VALIDATION_PATH.write_text(text, encoding="utf-8") + + +def repair_changelog() -> None: + text = CHANGELOG_PATH.read_text(encoding="utf-8") + bullets = ( + "- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.", + "- Required at least one evidence reference when a relationship command chooses the evidence-backed assertion path.", + "- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.", + ) + missing = [bullet for bullet in bullets if bullet not in text] + if missing: + marker = "## [Unreleased]" + if marker not in text: + marker = "## Unreleased" + if marker in text: + insertion = text.index("\n", text.index(marker)) + 1 + text = text[:insertion] + "\n### Fixed\n\n" + "\n".join(missing) + "\n" + text[insertion:] + else: + text += "\n## Unreleased\n\n### Fixed\n\n" + "\n".join(missing) + "\n" + CHANGELOG_PATH.write_text(text, encoding="utf-8") + + +def remove_temporary_artifacts() -> None: + for path_text in ( + ".github/workflows/repair-review-round-3.yml", + ".github/workflows/repair-review-round-4.yml", + ".github/workflows/repair-review-round-5.yml", + "tools/repair_contract_review_round5.py", + ): + path = ROOT / path_text + if path.exists(): + path.unlink() + + +def refresh_manifest() -> None: + manifest = json.loads(MANIFEST_PATH.read_text(encoding="utf-8")) + entries: list[dict[str, object]] = [] + for path in sorted(ROOT.rglob("*")): + if not path.is_file() or ".git" in path.parts or path == MANIFEST_PATH: + continue + payload = path.read_bytes() + entries.append( + { + "path": path.as_posix(), + "sha256": hashlib.sha256(payload).hexdigest(), + "size_bytes": len(payload), + "line_count": len(payload.decode("utf-8").splitlines()), + } + ) + if len(entries) != 55: + raise RuntimeError(f"expected 55 manifest entries after cleanup, found {len(entries)}") + manifest["generated_at"] = "2026-08-29T00:00:00Z" + manifest["file_count"] = len(entries) + manifest["files"] = entries + MANIFEST_PATH.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") + + +def validate_final_tree() -> None: + files = [path for path in ROOT.rglob("*") if path.is_file() and ".git" not in path.parts] + if len(files) != 56: + raise RuntimeError(f"expected 56 final files including manifest, found {len(files)}") + + manifest = json.loads(MANIFEST_PATH.read_text(encoding="utf-8")) + entries = {entry["path"]: entry for entry in manifest["files"]} + if manifest["file_count"] != len(entries) or len(entries) != 55: + raise RuntimeError("manifest inventory count mismatch") + for path_text, entry in entries.items(): + payload = Path(path_text).read_bytes() + if hashlib.sha256(payload).hexdigest() != entry["sha256"]: + raise RuntimeError(f"manifest hash mismatch: {path_text}") + if len(payload) != entry["size_bytes"]: + raise RuntimeError(f"manifest size mismatch: {path_text}") + if len(payload.decode("utf-8").splitlines()) != entry["line_count"]: + raise RuntimeError(f"manifest line-count mismatch: {path_text}") + + for path in sorted((ROOT / "schemas/events").glob("*.json")): + schema = json.loads(path.read_text(encoding="utf-8")) + if schema.get("$schema") != "https://json-schema.org/draft/2020-12/schema": + raise RuntimeError(f"schema declaration mismatch: {path}") + if schema.get("additionalProperties") is not False: + raise RuntimeError(f"schema must close unknown fields: {path}") + + +def main() -> None: + repair_openapi() + repair_validation_report() + repair_changelog() + PERMANENT_WORKFLOW_PATH.write_text(PERMANENT_WORKFLOW, encoding="utf-8") + remove_temporary_artifacts() + refresh_manifest() + validate_final_tree() + + +if __name__ == "__main__": + main() From 88ea9a9862beac8671effd37e93db47e3b75a69d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 06:24:31 -0700 Subject: [PATCH 32/87] ci: execute deterministic contract review repair --- .github/workflows/repair-review-round-5.yml | 38 +++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/repair-review-round-5.yml diff --git a/.github/workflows/repair-review-round-5.yml b/.github/workflows/repair-review-round-5.yml new file mode 100644 index 0000000..9b1234d --- /dev/null +++ b/.github/workflows/repair-review-round-5.yml @@ -0,0 +1,38 @@ +name: deterministic ELUNVERA contract review repair + +on: + push: + branches: + - docs/product-technical-baseline + workflow_dispatch: + +permissions: + contents: write + +jobs: + repair: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out triggering revision + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + + - name: Repair, validate, commit, and push + shell: bash + run: | + set -euo pipefail + test "$(git rev-parse HEAD)" = "$GITHUB_SHA" + python3 tools/repair_contract_review_round5.py + ruby -ryaml -e "YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false); YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false); YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false)" + git diff --check + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + test -n "$(git diff --cached --name-only)" + git commit -m "fix: close remaining contract review findings" + git push origin HEAD:docs/product-technical-baseline From 5e8d7120ddd905dfd1d026ccc42a1a53931269dd Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 06:34:03 -0700 Subject: [PATCH 33/87] ci: reconcile reviewed contract baseline atomically --- .../workflows/reconcile-contract-baseline.yml | 344 ++++++++++++++++++ 1 file changed, 344 insertions(+) create mode 100644 .github/workflows/reconcile-contract-baseline.yml diff --git a/.github/workflows/reconcile-contract-baseline.yml b/.github/workflows/reconcile-contract-baseline.yml new file mode 100644 index 0000000..72375dd --- /dev/null +++ b/.github/workflows/reconcile-contract-baseline.yml @@ -0,0 +1,344 @@ +name: reconcile reviewed ELUNVERA contract baseline + +on: + push: + branches: + - docs/product-technical-baseline + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: elunvera-contract-baseline-reconcile + cancel-in-progress: false + +jobs: + reconcile: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out triggering revision + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + ref: ${{ github.sha }} + fetch-depth: 0 + + - name: Reconcile, validate, commit, and push + shell: bash + run: | + set -euo pipefail + test "$(git rev-parse HEAD)" = "$GITHUB_SHA" + + python3 <<'PY' + from __future__ import annotations + + import hashlib + import json + import re + from pathlib import Path + + root = Path('.') + openapi_path = root / 'schemas/openapi.yaml' + asyncapi_path = root / 'schemas/asyncapi.yaml' + validation_path = root / 'docs/VALIDATION_REPORT.md' + changelog_path = root / 'CHANGELOG.md' + permanent_path = root / '.github/workflows/document-contracts.yml' + manifest_path = root / 'manifest.json' + + # P0 manual relationship commands cannot mint inferred truth. An + # evidence-backed assertion must also carry at least one reference. + openapi = openapi_path.read_text(encoding='utf-8') + start = openapi.index(' RecordRelationshipRequest:\n') + end = openapi.index(' StageTransitionRequest:\n', start) + relationship = openapi[start:end] + relationship = re.sub(r'(?m)^ - inferred\n', '', relationship) + evidence_header = ' evidence_reference_ids:\n type: array\n' + if ' evidence_reference_ids:\n type: array\n minItems:' not in relationship: + if evidence_header not in relationship: + raise RuntimeError('relationship evidence array not found') + relationship = relationship.replace( + evidence_header, + evidence_header + ' minItems: 1\n', + 1, + ) + relationship = re.sub( + r'( evidence_reference_ids:\n type: array\n minItems:)\s*\d+', + r'\g<1> 1', + relationship, + count=1, + ) + if ' - inferred\n' in relationship: + raise RuntimeError('manual relationship command still accepts inferred truth') + if ' minItems: 1\n' not in relationship: + raise RuntimeError('evidence-backed relationship command accepts an empty array') + openapi_path.write_text(openapi[:start] + relationship + openapi[end:], encoding='utf-8') + + # Remove every one-shot transfer/repair artifact before inventory is + # computed. The permanent branch must not depend on self-modifying CI. + temporary_paths = set() + for pattern in ( + '.github/workflows/repair-review-round-*.yml', + '.github/workflows/reconcile-contract-baseline.yml', + 'tools/repair_contract_review_round*.py', + ): + temporary_paths.update(root.glob(pattern)) + for path in sorted(temporary_paths): + if path.exists(): + path.unlink() + + permanent_workflow = r'''name: document and contract checks + +on: + pull_request: + branches: + - develop + push: + branches: + - develop + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: elunvera-document-contracts-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + validate: + name: validate documentation and contracts + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out exact revision + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Reject temporary repair artifacts + shell: bash + run: | + set -euo pipefail + test -z "$(find .github/workflows tools -type f \( -name 'repair-review-round-*.yml' -o -name 'reconcile-contract-baseline.yml' -o -name 'repair_contract_review_round*.py' \) -print 2>/dev/null)" + + - name: Parse and validate YAML contracts + shell: bash + run: | + set -euo pipefail + ruby -ryaml - <<'RUBY' + openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) + raise 'OpenAPI version mismatch' unless openapi.fetch('openapi') == '3.2.0' + + operations = [] + openapi.fetch('paths').each do |path, item| + item.each do |method, operation| + next unless %w[get post put patch delete head options trace].include?(method) + operations << [path, operation.fetch('operationId')] + end + end + raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length + + parameters = openapi.fetch('components').fetch('parameters') + %w[ValidAt RecordedAt KnowledgeCutoff].each do |name| + raise "missing temporal parameter #{name}" unless parameters.key?(name) + end + + relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') + truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') + raise 'manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred') + evidence = relationship.fetch('properties').fetch('evidence_reference_ids') + raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1 + + asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) + raise 'AsyncAPI version mismatch' unless asyncapi.fetch('asyncapi') == '3.1.0' + asyncapi.fetch('operations').each do |name, operation| + raise "#{name} must describe ELUNVERA as producer" unless operation.fetch('action') == 'send' + end + envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') + required = envelope.fetch('required') + raise 'provenance extension must be required' unless required.include?('provenanceref') + raise 'classification extension must be required' unless required.any? { |field| %w[dataclassification data_classification].include?(field) } + raise 'schema revision extension must be required' unless required.any? { |field| %w[schemarevision schema_revision].include?(field) } + RUBY + + - name: Validate manifest, event schemas, and durable evidence + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + import hashlib + import json + import re + import subprocess + from pathlib import Path + + tracked = set(subprocess.check_output(['git', 'ls-files'], text=True).splitlines()) + manifest_path = Path('manifest.json') + manifest = json.loads(manifest_path.read_text(encoding='utf-8')) + entries = {entry['path']: entry for entry in manifest['files']} + expected_entries = tracked - {'manifest.json'} + assert manifest['file_count'] == len(entries) == len(expected_entries) + assert set(entries) == expected_entries + for path_text, entry in entries.items(): + payload = Path(path_text).read_bytes() + assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text + assert len(payload) == entry['size_bytes'], path_text + assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text + + for event_path in sorted(Path('schemas/events').glob('*.json')): + schema = json.loads(event_path.read_text(encoding='utf-8')) + assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema' + assert schema['additionalProperties'] is False + relationship_event = json.loads(Path('schemas/events/relationship-changed-v1.schema.json').read_text(encoding='utf-8')) + assert 'recorded_at' in relationship_event['required'] + + report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') + tracked_match = re.search(r'Tracked repository files including `manifest\.json`: \*\*(\d+)\*\*', report) + entries_match = re.search(r'Manifest entries excluding `manifest\.json`: \*\*(\d+)\*\*', report) + assert tracked_match and int(tracked_match.group(1)) == len(tracked) + assert entries_match and int(entries_match.group(1)) == len(expected_entries) + assert 'Draft 2020-12 declaration and structural invariant validation' in report + assert 'metaschema validation' not in report.lower() + + placeholder = re.compile(r'\b(?:TBD|TODO|FIXME)\b') + for path in expected_entries: + if path.endswith(('.md', '.yaml', '.yml', '.json')): + assert not placeholder.search(Path(path).read_text(encoding='utf-8')), path + PY + + - name: Validate Markdown links and fences + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + import re + from pathlib import Path + + link_pattern = re.compile(r'(?') + if not target or target.startswith(('#', 'http://', 'https://', 'mailto:')): + continue + local = target.split('#', 1)[0] + if local: + assert (path.parent / local).resolve().exists(), f'broken link: {path} -> {target}' + PY + + - name: Reject whitespace errors + shell: bash + run: git diff --check HEAD^ +''' + permanent_path.write_text(permanent_workflow, encoding='utf-8') + + # Correct the durable validation claim and make its inventory reflect + # the actual final tracked tree rather than a stale hard-coded count. + final_files = sorted( + path for path in root.rglob('*') + if path.is_file() and '.git' not in path.parts + ) + if manifest_path not in final_files: + raise RuntimeError('manifest.json is missing from the final tree') + tracked_count = len(final_files) + manifest_entry_count = tracked_count - 1 + + validation = validation_path.read_text(encoding='utf-8') + validation = re.sub( + r'- \*\*Validation date:\*\* \d{4}-\d{2}-\d{2}', + '- **Validation date:** 2026-08-29', + validation, + count=1, + ) + validation = re.sub( + r'JSON Schema Draft 2020-12 metaschema validation', + 'JSON Schema Draft 2020-12 declaration and structural invariant validation', + validation, + flags=re.IGNORECASE, + ) + validation = validation.replace( + 'Python JSON and JSON Schema validation', + 'Python JSON parsing and Draft 2020-12 declaration/invariant validation', + ) + tracked_line = f'- Tracked repository files including `manifest.json`: **{tracked_count}**' + entry_line = f'- Manifest entries excluding `manifest.json`: **{manifest_entry_count}**' + if re.search(r'- (?:Repository|Tracked repository) files[^\n]*', validation): + validation = re.sub(r'- (?:Repository|Tracked repository) files[^\n]*', tracked_line, validation, count=1) + else: + validation += '\n' + tracked_line + '\n' + if re.search(r'- Manifest entries excluding `manifest\.json`[^\n]*', validation): + validation = re.sub(r'- Manifest entries excluding `manifest\.json`[^\n]*', entry_line, validation, count=1) + else: + validation += entry_line + '\n' + if 'metaschema validation' in validation.lower(): + raise RuntimeError('validation report still overstates metaschema validation') + validation_path.write_text(validation, encoding='utf-8') + + changelog = changelog_path.read_text(encoding='utf-8') + fixes = ( + '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.', + '- Required at least one evidence reference when the evidence-backed relationship assertion path is selected.', + '- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.', + ) + missing = [item for item in fixes if item not in changelog] + if missing: + changelog += '\n## Contract review repairs\n\n' + '\n'.join(missing) + '\n' + changelog_path.write_text(changelog, encoding='utf-8') + + # Refresh the manifest only after all final durable files are settled. + manifest = json.loads(manifest_path.read_text(encoding='utf-8')) + entries = [] + for path in sorted(root.rglob('*')): + if not path.is_file() or '.git' in path.parts or path == manifest_path: + continue + payload = path.read_bytes() + entries.append({ + 'path': path.as_posix(), + 'sha256': hashlib.sha256(payload).hexdigest(), + 'size_bytes': len(payload), + 'line_count': len(payload.decode('utf-8').splitlines()), + }) + if len(entries) != manifest_entry_count: + raise RuntimeError(f'manifest inventory mismatch: {len(entries)} != {manifest_entry_count}') + manifest['generated_at'] = '2026-08-29T00:00:00Z' + manifest['file_count'] = len(entries) + manifest['files'] = entries + manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') + + # Exact local verification of the final filesystem tree. + final_files = sorted(path for path in root.rglob('*') if path.is_file() and '.git' not in path.parts) + if len(final_files) != tracked_count: + raise RuntimeError('final file count changed during reconciliation') + entries_by_path = {entry['path']: entry for entry in entries} + for path_text, entry in entries_by_path.items(): + payload = Path(path_text).read_bytes() + if hashlib.sha256(payload).hexdigest() != entry['sha256']: + raise RuntimeError(f'manifest hash mismatch: {path_text}') + if len(payload) != entry['size_bytes']: + raise RuntimeError(f'manifest size mismatch: {path_text}') + json.loads((root / 'schemas/events/relationship-changed-v1.schema.json').read_text(encoding='utf-8')) + json.loads((root / 'schemas/events/opportunity-stage-changed-v1.schema.json').read_text(encoding='utf-8')) + PY + + ruby -ryaml - <<'RUBY' + openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) + relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') + raise 'inferred truth remains accepted' if relationship.fetch('properties').fetch('truth_status').fetch('enum').include?('inferred') + raise 'empty evidence array remains accepted' unless relationship.fetch('properties').fetch('evidence_reference_ids').fetch('minItems').to_i >= 1 + YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) + YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false) + RUBY + + git diff --check + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + test -n "$(git diff --cached --name-only)" + git commit -m "fix: reconcile reviewed contract baseline" + git push origin HEAD:docs/product-technical-baseline From 4f708cf7bb0b3378e2401b43b4ab69eae3c1d9c0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 06:37:47 -0700 Subject: [PATCH 34/87] ci: finalize permanent contract validation baseline --- .../reconcile-contract-baseline-v2.yml | 328 ++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 .github/workflows/reconcile-contract-baseline-v2.yml diff --git a/.github/workflows/reconcile-contract-baseline-v2.yml b/.github/workflows/reconcile-contract-baseline-v2.yml new file mode 100644 index 0000000..3dacdc3 --- /dev/null +++ b/.github/workflows/reconcile-contract-baseline-v2.yml @@ -0,0 +1,328 @@ +name: finalize permanent ELUNVERA contract validation + +on: + push: + branches: + - docs/product-technical-baseline + workflow_dispatch: + +permissions: + contents: write + +concurrency: + group: elunvera-contract-baseline-reconcile + cancel-in-progress: false + +jobs: + finalize: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out latest feature branch + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + ref: docs/product-technical-baseline + fetch-depth: 0 + + - name: Finalize, validate, commit, and push + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + from __future__ import annotations + + import hashlib + import json + import re + from pathlib import Path + + root = Path('.') + openapi_path = root / 'schemas/openapi.yaml' + validation_path = root / 'docs/VALIDATION_REPORT.md' + changelog_path = root / 'CHANGELOG.md' + workflow_path = root / '.github/workflows/document-contracts.yml' + manifest_path = root / 'manifest.json' + + openapi = openapi_path.read_text(encoding='utf-8') + start = openapi.index(' RecordRelationshipRequest:\n') + end = openapi.index(' StageTransitionRequest:\n', start) + relationship = openapi[start:end] + relationship = re.sub(r'(?m)^ - inferred\n', '', relationship) + evidence_header = ' evidence_reference_ids:\n type: array\n' + if ' evidence_reference_ids:\n type: array\n minItems:' not in relationship: + if evidence_header not in relationship: + raise RuntimeError('relationship evidence array not found') + relationship = relationship.replace(evidence_header, evidence_header + ' minItems: 1\n', 1) + relationship = re.sub( + r'( evidence_reference_ids:\n type: array\n minItems:)\s*\d+', + r'\g<1> 1', + relationship, + count=1, + ) + if ' - inferred\n' in relationship: + raise RuntimeError('manual relationship command still accepts inferred truth') + if ' minItems: 1\n' not in relationship: + raise RuntimeError('evidence-backed relationship assertion accepts an empty array') + openapi_path.write_text(openapi[:start] + relationship + openapi[end:], encoding='utf-8') + + permanent_template = r'''name: document and contract checks + +on: + pull_request: + branches: + - develop + push: + branches: + - develop + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: __GROUP_EXPRESSION__ + cancel-in-progress: true + +jobs: + validate: + name: validate documentation and contracts + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out exact revision + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Reject temporary repair artifacts + shell: bash + run: | + set -euo pipefail + test -z "$(find .github/workflows tools -type f \( -name 'repair-review-round-*.yml' -o -name 'reconcile-contract-baseline*.yml' -o -name 'repair_contract_review_round*.py' \) -print 2>/dev/null)" + + - name: Parse and validate YAML contracts + shell: bash + run: | + set -euo pipefail + ruby -ryaml - <<'RUBY' + openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) + raise 'OpenAPI version mismatch' unless openapi.fetch('openapi') == '3.2.0' + operations = [] + openapi.fetch('paths').each do |path, item| + item.each do |method, operation| + next unless %w[get post put patch delete head options trace].include?(method) + operations << [path, operation.fetch('operationId')] + end + end + raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length + parameters = openapi.fetch('components').fetch('parameters') + %w[ValidAt RecordedAt KnowledgeCutoff].each do |name| + raise "missing temporal parameter #{name}" unless parameters.key?(name) + end + relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') + truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') + raise 'manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred') + evidence = relationship.fetch('properties').fetch('evidence_reference_ids') + raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1 + + asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) + raise 'AsyncAPI version mismatch' unless asyncapi.fetch('asyncapi') == '3.1.0' + asyncapi.fetch('operations').each do |name, operation| + raise "#{name} must describe ELUNVERA as producer" unless operation.fetch('action') == 'send' + end + envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') + required = envelope.fetch('required') + raise 'provenance extension must be required' unless required.include?('provenanceref') + raise 'classification extension must be required' unless required.any? { |field| %w[dataclassification data_classification].include?(field) } + raise 'schema revision extension must be required' unless required.any? { |field| %w[schemarevision schema_revision].include?(field) } + RUBY + + - name: Validate manifest, event schemas, and durable evidence + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + import hashlib + import json + import re + import subprocess + from pathlib import Path + + tracked = set(subprocess.check_output(['git', 'ls-files'], text=True).splitlines()) + manifest_path = Path('manifest.json') + manifest = json.loads(manifest_path.read_text(encoding='utf-8')) + entries = {entry['path']: entry for entry in manifest['files']} + expected_entries = tracked - {'manifest.json'} + assert manifest['file_count'] == len(entries) == len(expected_entries) + assert set(entries) == expected_entries + for path_text, entry in entries.items(): + payload = Path(path_text).read_bytes() + assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text + assert len(payload) == entry['size_bytes'], path_text + assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text + + for event_path in sorted(Path('schemas/events').glob('*.json')): + schema = json.loads(event_path.read_text(encoding='utf-8')) + assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema' + assert schema['additionalProperties'] is False + relationship_event = json.loads(Path('schemas/events/relationship-changed-v1.schema.json').read_text(encoding='utf-8')) + assert 'recorded_at' in relationship_event['required'] + + report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') + tracked_match = re.search(r'Tracked repository files including `manifest\.json`: \*\*(\d+)\*\*', report) + entries_match = re.search(r'Manifest entries excluding `manifest\.json`: \*\*(\d+)\*\*', report) + assert tracked_match and int(tracked_match.group(1)) == len(tracked) + assert entries_match and int(entries_match.group(1)) == len(expected_entries) + assert 'Draft 2020-12 declaration and structural invariant validation' in report + assert 'metaschema validation' not in report.lower() + + placeholder = re.compile(r'\b(?:TBD|TODO|FIXME)\b') + for path in expected_entries: + if path.endswith(('.md', '.yaml', '.yml', '.json')): + assert not placeholder.search(Path(path).read_text(encoding='utf-8')), path + PY + + - name: Validate Markdown links and fences + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + import re + from pathlib import Path + + link_pattern = re.compile(r'(?') + if not target or target.startswith(('#', 'http://', 'https://', 'mailto:')): + continue + local = target.split('#', 1)[0] + if local: + assert (path.parent / local).resolve().exists(), f'broken link: {path} -> {target}' + PY + + - name: Reject whitespace errors + shell: bash + run: git diff --check HEAD^ +''' + workflow_path.write_text( + permanent_template.replace( + '__GROUP_EXPRESSION__', + '${{ github.event.pull_request.number || github.ref }}', + ), + encoding='utf-8', + ) + + for pattern in ( + '.github/workflows/repair-review-round-*.yml', + '.github/workflows/reconcile-contract-baseline*.yml', + 'tools/repair_contract_review_round*.py', + ): + for path in root.glob(pattern): + if path.exists(): + path.unlink() + + files_before_manifest = sorted(path for path in root.rglob('*') if path.is_file() and '.git' not in path.parts) + tracked_count = len(files_before_manifest) + entry_count = tracked_count - 1 + + validation = validation_path.read_text(encoding='utf-8') + validation = re.sub( + r'- \*\*Validation date:\*\* \d{4}-\d{2}-\d{2}', + '- **Validation date:** 2026-08-29', + validation, + count=1, + ) + validation = re.sub( + r'JSON Schema Draft 2020-12 metaschema validation', + 'JSON Schema Draft 2020-12 declaration and structural invariant validation', + validation, + flags=re.IGNORECASE, + ) + validation = validation.replace( + 'Python JSON and JSON Schema validation', + 'Python JSON parsing and Draft 2020-12 declaration/invariant validation', + ) + tracked_line = f'- Tracked repository files including `manifest.json`: **{tracked_count}**' + entry_line = f'- Manifest entries excluding `manifest.json`: **{entry_count}**' + validation = re.sub( + r'- (?:Repository|Tracked repository) files[^\n]*', + tracked_line, + validation, + count=1, + ) + validation = re.sub( + r'- Manifest entries excluding `manifest\.json`[^\n]*', + entry_line, + validation, + count=1, + ) + if tracked_line not in validation: + validation += '\n' + tracked_line + '\n' + if entry_line not in validation: + validation += entry_line + '\n' + if 'metaschema validation' in validation.lower(): + raise RuntimeError('validation report still overstates metaschema validation') + validation_path.write_text(validation, encoding='utf-8') + + changelog = changelog_path.read_text(encoding='utf-8') + fixes = ( + '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.', + '- Required at least one evidence reference when the evidence-backed relationship assertion path is selected.', + '- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.', + ) + missing = [item for item in fixes if item not in changelog] + if missing: + changelog += '\n## Contract review repairs\n\n' + '\n'.join(missing) + '\n' + changelog_path.write_text(changelog, encoding='utf-8') + + manifest = json.loads(manifest_path.read_text(encoding='utf-8')) + entries = [] + for path in sorted(root.rglob('*')): + if not path.is_file() or '.git' in path.parts or path == manifest_path: + continue + payload = path.read_bytes() + entries.append({ + 'path': path.as_posix(), + 'sha256': hashlib.sha256(payload).hexdigest(), + 'size_bytes': len(payload), + 'line_count': len(payload.decode('utf-8').splitlines()), + }) + if len(entries) != entry_count: + raise RuntimeError(f'manifest count mismatch: {len(entries)} != {entry_count}') + manifest['generated_at'] = '2026-08-29T00:00:00Z' + manifest['file_count'] = len(entries) + manifest['files'] = entries + manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') + + final_files = sorted(path for path in root.rglob('*') if path.is_file() and '.git' not in path.parts) + if len(final_files) != tracked_count: + raise RuntimeError('final file count changed during finalization') + for entry in entries: + payload = Path(entry['path']).read_bytes() + if hashlib.sha256(payload).hexdigest() != entry['sha256']: + raise RuntimeError(f"manifest hash mismatch: {entry['path']}") + PY + + ruby -ryaml - <<'RUBY' + openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) + relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') + raise 'inferred truth remains accepted' if relationship.fetch('properties').fetch('truth_status').fetch('enum').include?('inferred') + raise 'empty evidence array remains accepted' unless relationship.fetch('properties').fetch('evidence_reference_ids').fetch('minItems').to_i >= 1 + YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) + YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false) + RUBY + + git diff --check + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + test -n "$(git diff --cached --name-only)" + git commit -m "fix: finalize permanent contract validation baseline" + git push origin HEAD:docs/product-technical-baseline From d317c4a5560785592b37faf5f8d9887fd2a01965 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 06:41:46 -0700 Subject: [PATCH 35/87] ci: gate PR 2 on exact-head evidence --- .github/workflows/reconcile-and-gate-pr2.yml | 415 +++++++++++++++++++ 1 file changed, 415 insertions(+) create mode 100644 .github/workflows/reconcile-and-gate-pr2.yml diff --git a/.github/workflows/reconcile-and-gate-pr2.yml b/.github/workflows/reconcile-and-gate-pr2.yml new file mode 100644 index 0000000..be86e50 --- /dev/null +++ b/.github/workflows/reconcile-and-gate-pr2.yml @@ -0,0 +1,415 @@ +name: reconcile and safely gate ELUNVERA PR 2 + +on: + push: + branches: + - docs/product-technical-baseline + workflow_dispatch: + +permissions: + actions: read + checks: read + contents: write + issues: write + pull-requests: write + +concurrency: + group: elunvera-contract-baseline-reconcile + cancel-in-progress: false + +jobs: + reconcile-and-gate: + if: github.actor != 'github-actions[bot]' + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + GH_TOKEN: ${{ github.token }} + REPOSITORY: ${{ github.repository }} + PR_NUMBER: '2' + FEATURE_BRANCH: docs/product-technical-baseline + steps: + - name: Check out latest feature branch + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + ref: docs/product-technical-baseline + fetch-depth: 0 + + - name: Reconcile exact final tree and push + id: reconcile + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + from __future__ import annotations + + import hashlib + import json + import re + from pathlib import Path + + root = Path('.') + openapi_path = root / 'schemas/openapi.yaml' + validation_path = root / 'docs/VALIDATION_REPORT.md' + changelog_path = root / 'CHANGELOG.md' + workflow_path = root / '.github/workflows/document-contracts.yml' + manifest_path = root / 'manifest.json' + + openapi = openapi_path.read_text(encoding='utf-8') + start = openapi.index(' RecordRelationshipRequest:\n') + end = openapi.index(' StageTransitionRequest:\n', start) + relationship = openapi[start:end] + relationship = re.sub(r'(?m)^ - inferred\n', '', relationship) + evidence_header = ' evidence_reference_ids:\n type: array\n' + if ' evidence_reference_ids:\n type: array\n minItems:' not in relationship: + if evidence_header not in relationship: + raise RuntimeError('relationship evidence array not found') + relationship = relationship.replace(evidence_header, evidence_header + ' minItems: 1\n', 1) + relationship = re.sub( + r'( evidence_reference_ids:\n type: array\n minItems:)\s*\d+', + r'\g<1> 1', + relationship, + count=1, + ) + if ' - inferred\n' in relationship: + raise RuntimeError('manual relationship command still accepts inferred truth') + if ' minItems: 1\n' not in relationship: + raise RuntimeError('evidence-backed relationship assertion accepts an empty array') + openapi_path.write_text(openapi[:start] + relationship + openapi[end:], encoding='utf-8') + + permanent_template = r'''name: document and contract checks + +on: + pull_request: + branches: + - develop + push: + branches: + - develop + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: __GROUP_EXPRESSION__ + cancel-in-progress: true + +jobs: + validate: + name: validate documentation and contracts + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - name: Check out exact revision + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 + with: + fetch-depth: 0 + + - name: Reject temporary repair artifacts + shell: bash + run: | + set -euo pipefail + test -z "$(find .github/workflows tools -type f \( -name 'repair-review-round-*.yml' -o -name 'reconcile-contract-baseline*.yml' -o -name 'reconcile-and-gate-pr2.yml' -o -name 'repair_contract_review_round*.py' \) -print 2>/dev/null)" + + - name: Parse and validate YAML contracts + shell: bash + run: | + set -euo pipefail + ruby -ryaml - <<'RUBY' + openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) + raise 'OpenAPI version mismatch' unless openapi.fetch('openapi') == '3.2.0' + operations = [] + openapi.fetch('paths').each do |path, item| + item.each do |method, operation| + next unless %w[get post put patch delete head options trace].include?(method) + operations << [path, operation.fetch('operationId')] + end + end + raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length + parameters = openapi.fetch('components').fetch('parameters') + %w[ValidAt RecordedAt KnowledgeCutoff].each do |name| + raise "missing temporal parameter #{name}" unless parameters.key?(name) + end + relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') + truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') + raise 'manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred') + evidence = relationship.fetch('properties').fetch('evidence_reference_ids') + raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1 + + asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) + raise 'AsyncAPI version mismatch' unless asyncapi.fetch('asyncapi') == '3.1.0' + asyncapi.fetch('operations').each do |name, operation| + raise "#{name} must describe ELUNVERA as producer" unless operation.fetch('action') == 'send' + end + envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') + required = envelope.fetch('required') + raise 'provenance extension must be required' unless required.include?('provenanceref') + raise 'classification extension must be required' unless required.any? { |field| %w[dataclassification data_classification].include?(field) } + raise 'schema revision extension must be required' unless required.any? { |field| %w[schemarevision schema_revision].include?(field) } + RUBY + + - name: Validate manifest, event schemas, and durable evidence + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + import hashlib + import json + import re + import subprocess + from pathlib import Path + + tracked = set(subprocess.check_output(['git', 'ls-files'], text=True).splitlines()) + manifest_path = Path('manifest.json') + manifest = json.loads(manifest_path.read_text(encoding='utf-8')) + entries = {entry['path']: entry for entry in manifest['files']} + expected_entries = tracked - {'manifest.json'} + assert manifest['file_count'] == len(entries) == len(expected_entries) + assert set(entries) == expected_entries + for path_text, entry in entries.items(): + payload = Path(path_text).read_bytes() + assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text + assert len(payload) == entry['size_bytes'], path_text + assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text + + for event_path in sorted(Path('schemas/events').glob('*.json')): + schema = json.loads(event_path.read_text(encoding='utf-8')) + assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema' + assert schema['additionalProperties'] is False + relationship_event = json.loads(Path('schemas/events/relationship-changed-v1.schema.json').read_text(encoding='utf-8')) + assert 'recorded_at' in relationship_event['required'] + + report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') + tracked_match = re.search(r'Tracked repository files including `manifest\.json`: \*\*(\d+)\*\*', report) + entries_match = re.search(r'Manifest entries excluding `manifest\.json`: \*\*(\d+)\*\*', report) + assert tracked_match and int(tracked_match.group(1)) == len(tracked) + assert entries_match and int(entries_match.group(1)) == len(expected_entries) + assert 'Draft 2020-12 declaration and structural invariant validation' in report + assert 'metaschema validation' not in report.lower() + PY + + - name: Validate Markdown links, fences, and whitespace + shell: bash + run: | + set -euo pipefail + python3 <<'PY' + import re + from pathlib import Path + + link_pattern = re.compile(r'(?') + if not target or target.startswith(('#', 'http://', 'https://', 'mailto:')): + continue + local = target.split('#', 1)[0] + if local: + assert (path.parent / local).resolve().exists(), f'broken link: {path} -> {target}' + PY + git diff --check HEAD^ +''' + workflow_path.write_text( + permanent_template.replace( + '__GROUP_EXPRESSION__', + '${{ github.event.pull_request.number || github.ref }}', + ), + encoding='utf-8', + ) + + for pattern in ( + '.github/workflows/repair-review-round-*.yml', + '.github/workflows/reconcile-contract-baseline*.yml', + '.github/workflows/reconcile-and-gate-pr2.yml', + 'tools/repair_contract_review_round*.py', + ): + for path in root.glob(pattern): + if path.exists(): + path.unlink() + + final_files = sorted(path for path in root.rglob('*') if path.is_file() and '.git' not in path.parts) + if manifest_path not in final_files: + raise RuntimeError('manifest.json is missing') + tracked_count = len(final_files) + entry_count = tracked_count - 1 + + validation = validation_path.read_text(encoding='utf-8') + validation = re.sub(r'- \*\*Validation date:\*\* \d{4}-\d{2}-\d{2}', '- **Validation date:** 2026-08-29', validation, count=1) + validation = re.sub( + r'JSON Schema Draft 2020-12 metaschema validation', + 'JSON Schema Draft 2020-12 declaration and structural invariant validation', + validation, + flags=re.IGNORECASE, + ) + validation = validation.replace( + 'Python JSON and JSON Schema validation', + 'Python JSON parsing and Draft 2020-12 declaration/invariant validation', + ) + tracked_line = f'- Tracked repository files including `manifest.json`: **{tracked_count}**' + entry_line = f'- Manifest entries excluding `manifest.json`: **{entry_count}**' + validation = re.sub(r'- (?:Repository|Tracked repository) files[^\n]*', tracked_line, validation, count=1) + validation = re.sub(r'- Manifest entries excluding `manifest\.json`[^\n]*', entry_line, validation, count=1) + if tracked_line not in validation: + validation += '\n' + tracked_line + '\n' + if entry_line not in validation: + validation += entry_line + '\n' + if 'metaschema validation' in validation.lower(): + raise RuntimeError('validation report still overstates metaschema validation') + validation_path.write_text(validation, encoding='utf-8') + + changelog = changelog_path.read_text(encoding='utf-8') + fixes = ( + '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.', + '- Required at least one evidence reference when the evidence-backed relationship assertion path is selected.', + '- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.', + ) + missing = [item for item in fixes if item not in changelog] + if missing: + changelog += '\n## Contract review repairs\n\n' + '\n'.join(missing) + '\n' + changelog_path.write_text(changelog, encoding='utf-8') + + manifest = json.loads(manifest_path.read_text(encoding='utf-8')) + entries = [] + for path in sorted(root.rglob('*')): + if not path.is_file() or '.git' in path.parts or path == manifest_path: + continue + payload = path.read_bytes() + entries.append({ + 'path': path.as_posix(), + 'sha256': hashlib.sha256(payload).hexdigest(), + 'size_bytes': len(payload), + 'line_count': len(payload.decode('utf-8').splitlines()), + }) + if len(entries) != entry_count: + raise RuntimeError(f'manifest count mismatch: {len(entries)} != {entry_count}') + manifest['generated_at'] = '2026-08-29T00:00:00Z' + manifest['file_count'] = len(entries) + manifest['files'] = entries + manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') + PY + + ruby -ryaml - <<'RUBY' + openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) + relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') + raise 'inferred truth remains accepted' if relationship.fetch('properties').fetch('truth_status').fetch('enum').include?('inferred') + raise 'empty evidence array remains accepted' unless relationship.fetch('properties').fetch('evidence_reference_ids').fetch('minItems').to_i >= 1 + YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) + YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false) + RUBY + + git diff --check + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add -A + git diff --cached --check + test -n "$(git diff --cached --name-only)" + git commit -m "fix: finalize PR 2 exact-head contract evidence" + git push origin HEAD:docs/product-technical-baseline + echo "head_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" + + - name: Request exact-head independent review + shell: bash + run: | + set -euo pipefail + head_sha='${{ steps.reconcile.outputs.head_sha }}' + gh api --method POST "repos/$REPOSITORY/issues/$PR_NUMBER/comments" \ + -f body="@coderabbitai review + +Review exact head \`$head_sha\`. Revalidate all previous issues against current files. Report only current issues; confirm whether the P0 relationship assertion boundary, evidence cardinality, durable validation inventory, and temporary-artifact cleanup are correct." + + - name: Evaluate exact-head merge gate without bypass + id: gate + shell: bash + run: | + set -euo pipefail + head_sha='${{ steps.reconcile.outputs.head_sha }}' + gate_state='pending' + gate_reason='exact-head checks or independent review are not complete' + + for attempt in $(seq 1 60); do + pr_json="$(gh api "repos/$REPOSITORY/pulls/$PR_NUMBER")" + current_head="$(jq -r '.head.sha' <<<"$pr_json")" + current_base="$(jq -r '.base.ref' <<<"$pr_json")" + state="$(jq -r '.state' <<<"$pr_json")" + draft="$(jq -r '.draft' <<<"$pr_json")" + mergeable_state="$(jq -r '.mergeable_state // "unknown"' <<<"$pr_json")" + + if [[ "$state" != 'open' ]]; then + gate_state='closed' + gate_reason="PR state is $state" + break + fi + if [[ "$current_head" != "$head_sha" ]]; then + gate_state='superseded' + gate_reason="head changed from $head_sha to $current_head" + break + fi + if [[ "$current_base" != 'develop' || "$draft" != 'false' ]]; then + gate_reason="PR must target develop and be Ready for review" + sleep 10 + continue + fi + + checks_json="$(gh api -H 'Accept: application/vnd.github+json' "repos/$REPOSITORY/commits/$head_sha/check-runs?per_page=100")" + contract_success="$(jq '[.check_runs[] | select(.name == "validate documentation and contracts" and .status == "completed" and .conclusion == "success")] | length' <<<"$checks_json")" + failing_checks="$(jq '[.check_runs[] | select(.status == "completed" and (.conclusion | IN("failure", "cancelled", "timed_out", "action_required", "startup_failure", "stale")))] | length' <<<"$checks_json")" + + reviews_json="$(gh api --paginate "repos/$REPOSITORY/pulls/$PR_NUMBER/reviews?per_page=100" | jq -s 'add')" + exact_coderabbit_reviews="$(jq --arg sha "$head_sha" '[.[] | select((.user.login == "coderabbitai[bot]" or .user.login == "coderabbitai") and .commit_id == $sha)] | length' <<<"$reviews_json")" + actionable_review="$(jq --arg sha "$head_sha" '[.[] | select((.user.login == "coderabbitai[bot]" or .user.login == "coderabbitai") and .commit_id == $sha and ((.body // "") | test("Actionable comments posted: [1-9]|I found these contract issues|REQUEST_CHANGES"; "i")))] | length' <<<"$reviews_json")" + + threads_json="$(gh api graphql -f query='query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){pullRequest(number:$number){reviewThreads(first:100){nodes{isResolved comments(first:20){nodes{author{login}body commit{oid}}}}}}}}' -F owner="${REPOSITORY%/*}" -F name="${REPOSITORY#*/}" -F number="$PR_NUMBER")" + unresolved_threads="$(jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length' <<<"$threads_json")" + + comments_json="$(gh api --paginate "repos/$REPOSITORY/issues/$PR_NUMBER/comments?per_page=100" | jq -s 'add')" + rate_limited="$(jq '[.[] | select(.user.login == "coderabbitai[bot]" and ((.body // "") | test("Review limit reached|rate limited"; "i")))] | length' <<<"$comments_json")" + + if [[ "$contract_success" -ge 1 && "$failing_checks" -eq 0 && "$exact_coderabbit_reviews" -ge 1 && "$actionable_review" -eq 0 && "$unresolved_threads" -eq 0 && "$mergeable_state" == 'clean' ]]; then + gate_state='pass' + gate_reason="exact-head contract check passed; CodeRabbit reviewed the same head; no actionable or unresolved review items remain" + break + fi + + gate_reason="contract_success=$contract_success failing_checks=$failing_checks exact_coderabbit_reviews=$exact_coderabbit_reviews actionable_review=$actionable_review unresolved_threads=$unresolved_threads rate_limited=$rate_limited mergeable_state=$mergeable_state" + sleep 10 + done + + echo "state=$gate_state" >> "$GITHUB_OUTPUT" + echo "reason=$gate_reason" >> "$GITHUB_OUTPUT" + echo "head_sha=$head_sha" >> "$GITHUB_OUTPUT" + + - name: Squash merge through the normal protected path + if: steps.gate.outputs.state == 'pass' + shell: bash + run: | + set -euo pipefail + response="$(gh api --method PUT "repos/$REPOSITORY/pulls/$PR_NUMBER/merge" \ + -f sha='${{ steps.gate.outputs.head_sha }}' \ + -f merge_method='squash' \ + -f commit_title='docs: establish ELUNVERA product and technical baseline (#2)' \ + -f commit_message='Establish the reviewed product, architecture, data, API, privacy, security, UX, operability, standards, and delivery baseline for ELUNVERA.')" + merged="$(jq -r '.merged' <<<"$response")" + test "$merged" = 'true' + + - name: Record a non-merge gate result + if: steps.gate.outputs.state != 'pass' + shell: bash + run: | + set -euo pipefail + gh api --method POST "repos/$REPOSITORY/issues/$PR_NUMBER/comments" \ + -f body="Exact-head merge gate did not bypass repository policy and did not merge. + +- Head: \`${{ steps.gate.outputs.head_sha }}\` +- Gate state: \`${{ steps.gate.outputs.state }}\` +- Evidence: \`${{ steps.gate.outputs.reason }}\` + +The permanent contract workflow remains the source of check evidence. A later loop must re-read the live head, reviews, checks, and unresolved threads before merging." From e4812e58f7ea13b7e6e32b9dffd4a3902f60795d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 29 Aug 2026 06:58:43 -0700 Subject: [PATCH 36/87] ci: enable review on develop pull requests --- .coderabbit.yaml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .coderabbit.yaml diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000..d82aee4 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,6 @@ +reviews: + auto_review: + enabled: true + base_branches: + - develop + review_status: true From 8a42f569ea46b155775ff48bf406f972603a6e4a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 03:22:50 +0900 Subject: [PATCH 37/87] docs(metadata): add Ask DeepWiki badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 24b2ba3..1346b3b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # ELUNVERA +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/ContextualWisdomLab/ELUNVERA) + > **Every Link, Understood. Every Relationship, Activated.** ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence platform. It gives customer-facing teams a governed system of record for commercial accounts, stakeholders, interactions, commitments, opportunities, customer outcomes, and the decisions that connect them. From 695acca0e9c4060c22f19506ffa253cb450075b6 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 03:23:08 +0900 Subject: [PATCH 38/87] docs(metadata): add public documentation landing page --- docs/index.md | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 docs/index.md diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..1bfce12 --- /dev/null +++ b/docs/index.md @@ -0,0 +1,44 @@ +# ELUNVERA + +ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence platform for governed commercial accounts, stakeholders, interactions, commitments, opportunities, customer outcomes, and the decisions that connect them. + +[Ask DeepWiki](https://deepwiki.com/ContextualWisdomLab/ELUNVERA) + +## Start here + +- [Repository README](../README.md) — product promise, bounded responsibility, development status, and documentation map. +- [Product requirements](PRD.md) — users, jobs, requirements, scope, and release criteria. +- [Technical requirements](TRD.md) — platform constraints and implementation contracts. +- [Architecture](ARCHITECTURE.md) — bounded contexts, components, trust zones, and deployment model. +- [Canonical data model](DATA_MODEL.md) — temporal commercial facts, entities, ERD, and invariants. +- [API contract](API_CONTRACT.md) — HTTP, events, idempotency, pagination, concurrency, and compatibility. +- [Security](SECURITY.md) and [threat model](THREAT_MODEL.md) — product security boundaries and abuse-case treatment. +- [Privacy](PRIVACY.md) — purpose limitation, communication preferences, retention, disclosure, and data-rights workflows. +- [Test strategy](TEST_STRATEGY.md) — TDD, contract, security, coverage, and realistic validation expectations. +- [Operability](OPERABILITY.md) — SLO, telemetry, backup, recovery, and incident-response expectations. +- [UX specification](UX_SPEC.md) — information architecture and interaction principles. +- [Architecture decisions](adr/README.md) — accepted and proposed product/technical decisions. +- [Product/technical gap baseline](product-technical-gap-baseline.md) — current evidence, missing capabilities, and next actions. +- [Research and standards references](doctoring/REFERENCES.md) — APA-style source register. + +## Product boundary + +ELUNVERA owns tenant-scoped commercial relationship truth and its evidence, review state, temporal history, privacy metadata, opportunities, commitments, outcomes, complaints, and satisfaction observations. Identity and federation remain owned by Keyverse; mail, calendar, and file interaction remain with the products that originate them; reusable threading, lineage, retrieval fusion, model routing, psychometrics, ontology/catalog, generalized project execution, and billing retain their own ContextualWisdomLab authorities. + +Model output is evidence for review, not an automatic mutation of authoritative CRM truth. Graph, search, and vector representations are projections over the canonical governed record rather than competing systems of record. + +## Current maturity + +The current reviewed source is a documentation and machine-readable contract baseline. It does not, by itself, prove an implemented production service, database migration, hosted user interface, benchmark, security certification, accessibility conformance, customer deployment, or release. Those claims require executable artifacts and current-head verification evidence. + +## Onboarding and verification + +Begin with the PRD, TRD, architecture, data model, and API contract before implementing a product slice. The repository's permanent document/contract workflow and current protected-branch checks remain the integration authority. Any implementation must preserve the documented bitemporal/evidence model, normalized PostgreSQL system-of-record boundary, explicit service contracts, accessibility target, and security/privacy constraints. + +## Releases and deeper exploration + +- [GitHub Releases](https://github.com/ContextualWisdomLab/ELUNVERA/releases) +- [Ask DeepWiki](https://deepwiki.com/ContextualWisdomLab/ELUNVERA) +- [ContextualWisdomLab](https://github.com/ContextualWisdomLab) + +This is a public documentation landing source. GitHub Pages is considered published only after the source is integrated to the protected default branch, repository settings and deployment succeed, and the live HTTPS content is verified. From 1a828444302d306dba4c0967f9677c8f80995884 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:27:36 +0900 Subject: [PATCH 39/87] ci: remove one-shot reconciliation workflow --- .github/workflows/reconcile-and-gate-pr2.yml | 415 ------------------- 1 file changed, 415 deletions(-) delete mode 100644 .github/workflows/reconcile-and-gate-pr2.yml diff --git a/.github/workflows/reconcile-and-gate-pr2.yml b/.github/workflows/reconcile-and-gate-pr2.yml deleted file mode 100644 index be86e50..0000000 --- a/.github/workflows/reconcile-and-gate-pr2.yml +++ /dev/null @@ -1,415 +0,0 @@ -name: reconcile and safely gate ELUNVERA PR 2 - -on: - push: - branches: - - docs/product-technical-baseline - workflow_dispatch: - -permissions: - actions: read - checks: read - contents: write - issues: write - pull-requests: write - -concurrency: - group: elunvera-contract-baseline-reconcile - cancel-in-progress: false - -jobs: - reconcile-and-gate: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - timeout-minutes: 15 - env: - GH_TOKEN: ${{ github.token }} - REPOSITORY: ${{ github.repository }} - PR_NUMBER: '2' - FEATURE_BRANCH: docs/product-technical-baseline - steps: - - name: Check out latest feature branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - ref: docs/product-technical-baseline - fetch-depth: 0 - - - name: Reconcile exact final tree and push - id: reconcile - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - from __future__ import annotations - - import hashlib - import json - import re - from pathlib import Path - - root = Path('.') - openapi_path = root / 'schemas/openapi.yaml' - validation_path = root / 'docs/VALIDATION_REPORT.md' - changelog_path = root / 'CHANGELOG.md' - workflow_path = root / '.github/workflows/document-contracts.yml' - manifest_path = root / 'manifest.json' - - openapi = openapi_path.read_text(encoding='utf-8') - start = openapi.index(' RecordRelationshipRequest:\n') - end = openapi.index(' StageTransitionRequest:\n', start) - relationship = openapi[start:end] - relationship = re.sub(r'(?m)^ - inferred\n', '', relationship) - evidence_header = ' evidence_reference_ids:\n type: array\n' - if ' evidence_reference_ids:\n type: array\n minItems:' not in relationship: - if evidence_header not in relationship: - raise RuntimeError('relationship evidence array not found') - relationship = relationship.replace(evidence_header, evidence_header + ' minItems: 1\n', 1) - relationship = re.sub( - r'( evidence_reference_ids:\n type: array\n minItems:)\s*\d+', - r'\g<1> 1', - relationship, - count=1, - ) - if ' - inferred\n' in relationship: - raise RuntimeError('manual relationship command still accepts inferred truth') - if ' minItems: 1\n' not in relationship: - raise RuntimeError('evidence-backed relationship assertion accepts an empty array') - openapi_path.write_text(openapi[:start] + relationship + openapi[end:], encoding='utf-8') - - permanent_template = r'''name: document and contract checks - -on: - pull_request: - branches: - - develop - push: - branches: - - develop - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: __GROUP_EXPRESSION__ - cancel-in-progress: true - -jobs: - validate: - name: validate documentation and contracts - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out exact revision - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - fetch-depth: 0 - - - name: Reject temporary repair artifacts - shell: bash - run: | - set -euo pipefail - test -z "$(find .github/workflows tools -type f \( -name 'repair-review-round-*.yml' -o -name 'reconcile-contract-baseline*.yml' -o -name 'reconcile-and-gate-pr2.yml' -o -name 'repair_contract_review_round*.py' \) -print 2>/dev/null)" - - - name: Parse and validate YAML contracts - shell: bash - run: | - set -euo pipefail - ruby -ryaml - <<'RUBY' - openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) - raise 'OpenAPI version mismatch' unless openapi.fetch('openapi') == '3.2.0' - operations = [] - openapi.fetch('paths').each do |path, item| - item.each do |method, operation| - next unless %w[get post put patch delete head options trace].include?(method) - operations << [path, operation.fetch('operationId')] - end - end - raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length - parameters = openapi.fetch('components').fetch('parameters') - %w[ValidAt RecordedAt KnowledgeCutoff].each do |name| - raise "missing temporal parameter #{name}" unless parameters.key?(name) - end - relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') - truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') - raise 'manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred') - evidence = relationship.fetch('properties').fetch('evidence_reference_ids') - raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1 - - asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) - raise 'AsyncAPI version mismatch' unless asyncapi.fetch('asyncapi') == '3.1.0' - asyncapi.fetch('operations').each do |name, operation| - raise "#{name} must describe ELUNVERA as producer" unless operation.fetch('action') == 'send' - end - envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') - required = envelope.fetch('required') - raise 'provenance extension must be required' unless required.include?('provenanceref') - raise 'classification extension must be required' unless required.any? { |field| %w[dataclassification data_classification].include?(field) } - raise 'schema revision extension must be required' unless required.any? { |field| %w[schemarevision schema_revision].include?(field) } - RUBY - - - name: Validate manifest, event schemas, and durable evidence - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - import hashlib - import json - import re - import subprocess - from pathlib import Path - - tracked = set(subprocess.check_output(['git', 'ls-files'], text=True).splitlines()) - manifest_path = Path('manifest.json') - manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - entries = {entry['path']: entry for entry in manifest['files']} - expected_entries = tracked - {'manifest.json'} - assert manifest['file_count'] == len(entries) == len(expected_entries) - assert set(entries) == expected_entries - for path_text, entry in entries.items(): - payload = Path(path_text).read_bytes() - assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text - assert len(payload) == entry['size_bytes'], path_text - assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text - - for event_path in sorted(Path('schemas/events').glob('*.json')): - schema = json.loads(event_path.read_text(encoding='utf-8')) - assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema' - assert schema['additionalProperties'] is False - relationship_event = json.loads(Path('schemas/events/relationship-changed-v1.schema.json').read_text(encoding='utf-8')) - assert 'recorded_at' in relationship_event['required'] - - report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') - tracked_match = re.search(r'Tracked repository files including `manifest\.json`: \*\*(\d+)\*\*', report) - entries_match = re.search(r'Manifest entries excluding `manifest\.json`: \*\*(\d+)\*\*', report) - assert tracked_match and int(tracked_match.group(1)) == len(tracked) - assert entries_match and int(entries_match.group(1)) == len(expected_entries) - assert 'Draft 2020-12 declaration and structural invariant validation' in report - assert 'metaschema validation' not in report.lower() - PY - - - name: Validate Markdown links, fences, and whitespace - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - import re - from pathlib import Path - - link_pattern = re.compile(r'(?') - if not target or target.startswith(('#', 'http://', 'https://', 'mailto:')): - continue - local = target.split('#', 1)[0] - if local: - assert (path.parent / local).resolve().exists(), f'broken link: {path} -> {target}' - PY - git diff --check HEAD^ -''' - workflow_path.write_text( - permanent_template.replace( - '__GROUP_EXPRESSION__', - '${{ github.event.pull_request.number || github.ref }}', - ), - encoding='utf-8', - ) - - for pattern in ( - '.github/workflows/repair-review-round-*.yml', - '.github/workflows/reconcile-contract-baseline*.yml', - '.github/workflows/reconcile-and-gate-pr2.yml', - 'tools/repair_contract_review_round*.py', - ): - for path in root.glob(pattern): - if path.exists(): - path.unlink() - - final_files = sorted(path for path in root.rglob('*') if path.is_file() and '.git' not in path.parts) - if manifest_path not in final_files: - raise RuntimeError('manifest.json is missing') - tracked_count = len(final_files) - entry_count = tracked_count - 1 - - validation = validation_path.read_text(encoding='utf-8') - validation = re.sub(r'- \*\*Validation date:\*\* \d{4}-\d{2}-\d{2}', '- **Validation date:** 2026-08-29', validation, count=1) - validation = re.sub( - r'JSON Schema Draft 2020-12 metaschema validation', - 'JSON Schema Draft 2020-12 declaration and structural invariant validation', - validation, - flags=re.IGNORECASE, - ) - validation = validation.replace( - 'Python JSON and JSON Schema validation', - 'Python JSON parsing and Draft 2020-12 declaration/invariant validation', - ) - tracked_line = f'- Tracked repository files including `manifest.json`: **{tracked_count}**' - entry_line = f'- Manifest entries excluding `manifest.json`: **{entry_count}**' - validation = re.sub(r'- (?:Repository|Tracked repository) files[^\n]*', tracked_line, validation, count=1) - validation = re.sub(r'- Manifest entries excluding `manifest\.json`[^\n]*', entry_line, validation, count=1) - if tracked_line not in validation: - validation += '\n' + tracked_line + '\n' - if entry_line not in validation: - validation += entry_line + '\n' - if 'metaschema validation' in validation.lower(): - raise RuntimeError('validation report still overstates metaschema validation') - validation_path.write_text(validation, encoding='utf-8') - - changelog = changelog_path.read_text(encoding='utf-8') - fixes = ( - '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.', - '- Required at least one evidence reference when the evidence-backed relationship assertion path is selected.', - '- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.', - ) - missing = [item for item in fixes if item not in changelog] - if missing: - changelog += '\n## Contract review repairs\n\n' + '\n'.join(missing) + '\n' - changelog_path.write_text(changelog, encoding='utf-8') - - manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - entries = [] - for path in sorted(root.rglob('*')): - if not path.is_file() or '.git' in path.parts or path == manifest_path: - continue - payload = path.read_bytes() - entries.append({ - 'path': path.as_posix(), - 'sha256': hashlib.sha256(payload).hexdigest(), - 'size_bytes': len(payload), - 'line_count': len(payload.decode('utf-8').splitlines()), - }) - if len(entries) != entry_count: - raise RuntimeError(f'manifest count mismatch: {len(entries)} != {entry_count}') - manifest['generated_at'] = '2026-08-29T00:00:00Z' - manifest['file_count'] = len(entries) - manifest['files'] = entries - manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') - PY - - ruby -ryaml - <<'RUBY' - openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) - relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') - raise 'inferred truth remains accepted' if relationship.fetch('properties').fetch('truth_status').fetch('enum').include?('inferred') - raise 'empty evidence array remains accepted' unless relationship.fetch('properties').fetch('evidence_reference_ids').fetch('minItems').to_i >= 1 - YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) - YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false) - RUBY - - git diff --check - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - test -n "$(git diff --cached --name-only)" - git commit -m "fix: finalize PR 2 exact-head contract evidence" - git push origin HEAD:docs/product-technical-baseline - echo "head_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" - - - name: Request exact-head independent review - shell: bash - run: | - set -euo pipefail - head_sha='${{ steps.reconcile.outputs.head_sha }}' - gh api --method POST "repos/$REPOSITORY/issues/$PR_NUMBER/comments" \ - -f body="@coderabbitai review - -Review exact head \`$head_sha\`. Revalidate all previous issues against current files. Report only current issues; confirm whether the P0 relationship assertion boundary, evidence cardinality, durable validation inventory, and temporary-artifact cleanup are correct." - - - name: Evaluate exact-head merge gate without bypass - id: gate - shell: bash - run: | - set -euo pipefail - head_sha='${{ steps.reconcile.outputs.head_sha }}' - gate_state='pending' - gate_reason='exact-head checks or independent review are not complete' - - for attempt in $(seq 1 60); do - pr_json="$(gh api "repos/$REPOSITORY/pulls/$PR_NUMBER")" - current_head="$(jq -r '.head.sha' <<<"$pr_json")" - current_base="$(jq -r '.base.ref' <<<"$pr_json")" - state="$(jq -r '.state' <<<"$pr_json")" - draft="$(jq -r '.draft' <<<"$pr_json")" - mergeable_state="$(jq -r '.mergeable_state // "unknown"' <<<"$pr_json")" - - if [[ "$state" != 'open' ]]; then - gate_state='closed' - gate_reason="PR state is $state" - break - fi - if [[ "$current_head" != "$head_sha" ]]; then - gate_state='superseded' - gate_reason="head changed from $head_sha to $current_head" - break - fi - if [[ "$current_base" != 'develop' || "$draft" != 'false' ]]; then - gate_reason="PR must target develop and be Ready for review" - sleep 10 - continue - fi - - checks_json="$(gh api -H 'Accept: application/vnd.github+json' "repos/$REPOSITORY/commits/$head_sha/check-runs?per_page=100")" - contract_success="$(jq '[.check_runs[] | select(.name == "validate documentation and contracts" and .status == "completed" and .conclusion == "success")] | length' <<<"$checks_json")" - failing_checks="$(jq '[.check_runs[] | select(.status == "completed" and (.conclusion | IN("failure", "cancelled", "timed_out", "action_required", "startup_failure", "stale")))] | length' <<<"$checks_json")" - - reviews_json="$(gh api --paginate "repos/$REPOSITORY/pulls/$PR_NUMBER/reviews?per_page=100" | jq -s 'add')" - exact_coderabbit_reviews="$(jq --arg sha "$head_sha" '[.[] | select((.user.login == "coderabbitai[bot]" or .user.login == "coderabbitai") and .commit_id == $sha)] | length' <<<"$reviews_json")" - actionable_review="$(jq --arg sha "$head_sha" '[.[] | select((.user.login == "coderabbitai[bot]" or .user.login == "coderabbitai") and .commit_id == $sha and ((.body // "") | test("Actionable comments posted: [1-9]|I found these contract issues|REQUEST_CHANGES"; "i")))] | length' <<<"$reviews_json")" - - threads_json="$(gh api graphql -f query='query($owner:String!,$name:String!,$number:Int!){repository(owner:$owner,name:$name){pullRequest(number:$number){reviewThreads(first:100){nodes{isResolved comments(first:20){nodes{author{login}body commit{oid}}}}}}}}' -F owner="${REPOSITORY%/*}" -F name="${REPOSITORY#*/}" -F number="$PR_NUMBER")" - unresolved_threads="$(jq '[.data.repository.pullRequest.reviewThreads.nodes[] | select(.isResolved == false)] | length' <<<"$threads_json")" - - comments_json="$(gh api --paginate "repos/$REPOSITORY/issues/$PR_NUMBER/comments?per_page=100" | jq -s 'add')" - rate_limited="$(jq '[.[] | select(.user.login == "coderabbitai[bot]" and ((.body // "") | test("Review limit reached|rate limited"; "i")))] | length' <<<"$comments_json")" - - if [[ "$contract_success" -ge 1 && "$failing_checks" -eq 0 && "$exact_coderabbit_reviews" -ge 1 && "$actionable_review" -eq 0 && "$unresolved_threads" -eq 0 && "$mergeable_state" == 'clean' ]]; then - gate_state='pass' - gate_reason="exact-head contract check passed; CodeRabbit reviewed the same head; no actionable or unresolved review items remain" - break - fi - - gate_reason="contract_success=$contract_success failing_checks=$failing_checks exact_coderabbit_reviews=$exact_coderabbit_reviews actionable_review=$actionable_review unresolved_threads=$unresolved_threads rate_limited=$rate_limited mergeable_state=$mergeable_state" - sleep 10 - done - - echo "state=$gate_state" >> "$GITHUB_OUTPUT" - echo "reason=$gate_reason" >> "$GITHUB_OUTPUT" - echo "head_sha=$head_sha" >> "$GITHUB_OUTPUT" - - - name: Squash merge through the normal protected path - if: steps.gate.outputs.state == 'pass' - shell: bash - run: | - set -euo pipefail - response="$(gh api --method PUT "repos/$REPOSITORY/pulls/$PR_NUMBER/merge" \ - -f sha='${{ steps.gate.outputs.head_sha }}' \ - -f merge_method='squash' \ - -f commit_title='docs: establish ELUNVERA product and technical baseline (#2)' \ - -f commit_message='Establish the reviewed product, architecture, data, API, privacy, security, UX, operability, standards, and delivery baseline for ELUNVERA.')" - merged="$(jq -r '.merged' <<<"$response")" - test "$merged" = 'true' - - - name: Record a non-merge gate result - if: steps.gate.outputs.state != 'pass' - shell: bash - run: | - set -euo pipefail - gh api --method POST "repos/$REPOSITORY/issues/$PR_NUMBER/comments" \ - -f body="Exact-head merge gate did not bypass repository policy and did not merge. - -- Head: \`${{ steps.gate.outputs.head_sha }}\` -- Gate state: \`${{ steps.gate.outputs.state }}\` -- Evidence: \`${{ steps.gate.outputs.reason }}\` - -The permanent contract workflow remains the source of check evidence. A later loop must re-read the live head, reviews, checks, and unresolved threads before merging." From 3f068c81f763419ee92cbc67ec7b1f51e04168a9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:27:40 +0900 Subject: [PATCH 40/87] ci: remove superseded reconciliation workflow --- .../reconcile-contract-baseline-v2.yml | 328 ------------------ 1 file changed, 328 deletions(-) delete mode 100644 .github/workflows/reconcile-contract-baseline-v2.yml diff --git a/.github/workflows/reconcile-contract-baseline-v2.yml b/.github/workflows/reconcile-contract-baseline-v2.yml deleted file mode 100644 index 3dacdc3..0000000 --- a/.github/workflows/reconcile-contract-baseline-v2.yml +++ /dev/null @@ -1,328 +0,0 @@ -name: finalize permanent ELUNVERA contract validation - -on: - push: - branches: - - docs/product-technical-baseline - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: elunvera-contract-baseline-reconcile - cancel-in-progress: false - -jobs: - finalize: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out latest feature branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - ref: docs/product-technical-baseline - fetch-depth: 0 - - - name: Finalize, validate, commit, and push - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - from __future__ import annotations - - import hashlib - import json - import re - from pathlib import Path - - root = Path('.') - openapi_path = root / 'schemas/openapi.yaml' - validation_path = root / 'docs/VALIDATION_REPORT.md' - changelog_path = root / 'CHANGELOG.md' - workflow_path = root / '.github/workflows/document-contracts.yml' - manifest_path = root / 'manifest.json' - - openapi = openapi_path.read_text(encoding='utf-8') - start = openapi.index(' RecordRelationshipRequest:\n') - end = openapi.index(' StageTransitionRequest:\n', start) - relationship = openapi[start:end] - relationship = re.sub(r'(?m)^ - inferred\n', '', relationship) - evidence_header = ' evidence_reference_ids:\n type: array\n' - if ' evidence_reference_ids:\n type: array\n minItems:' not in relationship: - if evidence_header not in relationship: - raise RuntimeError('relationship evidence array not found') - relationship = relationship.replace(evidence_header, evidence_header + ' minItems: 1\n', 1) - relationship = re.sub( - r'( evidence_reference_ids:\n type: array\n minItems:)\s*\d+', - r'\g<1> 1', - relationship, - count=1, - ) - if ' - inferred\n' in relationship: - raise RuntimeError('manual relationship command still accepts inferred truth') - if ' minItems: 1\n' not in relationship: - raise RuntimeError('evidence-backed relationship assertion accepts an empty array') - openapi_path.write_text(openapi[:start] + relationship + openapi[end:], encoding='utf-8') - - permanent_template = r'''name: document and contract checks - -on: - pull_request: - branches: - - develop - push: - branches: - - develop - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: __GROUP_EXPRESSION__ - cancel-in-progress: true - -jobs: - validate: - name: validate documentation and contracts - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out exact revision - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - fetch-depth: 0 - - - name: Reject temporary repair artifacts - shell: bash - run: | - set -euo pipefail - test -z "$(find .github/workflows tools -type f \( -name 'repair-review-round-*.yml' -o -name 'reconcile-contract-baseline*.yml' -o -name 'repair_contract_review_round*.py' \) -print 2>/dev/null)" - - - name: Parse and validate YAML contracts - shell: bash - run: | - set -euo pipefail - ruby -ryaml - <<'RUBY' - openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) - raise 'OpenAPI version mismatch' unless openapi.fetch('openapi') == '3.2.0' - operations = [] - openapi.fetch('paths').each do |path, item| - item.each do |method, operation| - next unless %w[get post put patch delete head options trace].include?(method) - operations << [path, operation.fetch('operationId')] - end - end - raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length - parameters = openapi.fetch('components').fetch('parameters') - %w[ValidAt RecordedAt KnowledgeCutoff].each do |name| - raise "missing temporal parameter #{name}" unless parameters.key?(name) - end - relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') - truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') - raise 'manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred') - evidence = relationship.fetch('properties').fetch('evidence_reference_ids') - raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1 - - asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) - raise 'AsyncAPI version mismatch' unless asyncapi.fetch('asyncapi') == '3.1.0' - asyncapi.fetch('operations').each do |name, operation| - raise "#{name} must describe ELUNVERA as producer" unless operation.fetch('action') == 'send' - end - envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') - required = envelope.fetch('required') - raise 'provenance extension must be required' unless required.include?('provenanceref') - raise 'classification extension must be required' unless required.any? { |field| %w[dataclassification data_classification].include?(field) } - raise 'schema revision extension must be required' unless required.any? { |field| %w[schemarevision schema_revision].include?(field) } - RUBY - - - name: Validate manifest, event schemas, and durable evidence - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - import hashlib - import json - import re - import subprocess - from pathlib import Path - - tracked = set(subprocess.check_output(['git', 'ls-files'], text=True).splitlines()) - manifest_path = Path('manifest.json') - manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - entries = {entry['path']: entry for entry in manifest['files']} - expected_entries = tracked - {'manifest.json'} - assert manifest['file_count'] == len(entries) == len(expected_entries) - assert set(entries) == expected_entries - for path_text, entry in entries.items(): - payload = Path(path_text).read_bytes() - assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text - assert len(payload) == entry['size_bytes'], path_text - assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text - - for event_path in sorted(Path('schemas/events').glob('*.json')): - schema = json.loads(event_path.read_text(encoding='utf-8')) - assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema' - assert schema['additionalProperties'] is False - relationship_event = json.loads(Path('schemas/events/relationship-changed-v1.schema.json').read_text(encoding='utf-8')) - assert 'recorded_at' in relationship_event['required'] - - report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') - tracked_match = re.search(r'Tracked repository files including `manifest\.json`: \*\*(\d+)\*\*', report) - entries_match = re.search(r'Manifest entries excluding `manifest\.json`: \*\*(\d+)\*\*', report) - assert tracked_match and int(tracked_match.group(1)) == len(tracked) - assert entries_match and int(entries_match.group(1)) == len(expected_entries) - assert 'Draft 2020-12 declaration and structural invariant validation' in report - assert 'metaschema validation' not in report.lower() - - placeholder = re.compile(r'\b(?:TBD|TODO|FIXME)\b') - for path in expected_entries: - if path.endswith(('.md', '.yaml', '.yml', '.json')): - assert not placeholder.search(Path(path).read_text(encoding='utf-8')), path - PY - - - name: Validate Markdown links and fences - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - import re - from pathlib import Path - - link_pattern = re.compile(r'(?') - if not target or target.startswith(('#', 'http://', 'https://', 'mailto:')): - continue - local = target.split('#', 1)[0] - if local: - assert (path.parent / local).resolve().exists(), f'broken link: {path} -> {target}' - PY - - - name: Reject whitespace errors - shell: bash - run: git diff --check HEAD^ -''' - workflow_path.write_text( - permanent_template.replace( - '__GROUP_EXPRESSION__', - '${{ github.event.pull_request.number || github.ref }}', - ), - encoding='utf-8', - ) - - for pattern in ( - '.github/workflows/repair-review-round-*.yml', - '.github/workflows/reconcile-contract-baseline*.yml', - 'tools/repair_contract_review_round*.py', - ): - for path in root.glob(pattern): - if path.exists(): - path.unlink() - - files_before_manifest = sorted(path for path in root.rglob('*') if path.is_file() and '.git' not in path.parts) - tracked_count = len(files_before_manifest) - entry_count = tracked_count - 1 - - validation = validation_path.read_text(encoding='utf-8') - validation = re.sub( - r'- \*\*Validation date:\*\* \d{4}-\d{2}-\d{2}', - '- **Validation date:** 2026-08-29', - validation, - count=1, - ) - validation = re.sub( - r'JSON Schema Draft 2020-12 metaschema validation', - 'JSON Schema Draft 2020-12 declaration and structural invariant validation', - validation, - flags=re.IGNORECASE, - ) - validation = validation.replace( - 'Python JSON and JSON Schema validation', - 'Python JSON parsing and Draft 2020-12 declaration/invariant validation', - ) - tracked_line = f'- Tracked repository files including `manifest.json`: **{tracked_count}**' - entry_line = f'- Manifest entries excluding `manifest.json`: **{entry_count}**' - validation = re.sub( - r'- (?:Repository|Tracked repository) files[^\n]*', - tracked_line, - validation, - count=1, - ) - validation = re.sub( - r'- Manifest entries excluding `manifest\.json`[^\n]*', - entry_line, - validation, - count=1, - ) - if tracked_line not in validation: - validation += '\n' + tracked_line + '\n' - if entry_line not in validation: - validation += entry_line + '\n' - if 'metaschema validation' in validation.lower(): - raise RuntimeError('validation report still overstates metaschema validation') - validation_path.write_text(validation, encoding='utf-8') - - changelog = changelog_path.read_text(encoding='utf-8') - fixes = ( - '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.', - '- Required at least one evidence reference when the evidence-backed relationship assertion path is selected.', - '- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.', - ) - missing = [item for item in fixes if item not in changelog] - if missing: - changelog += '\n## Contract review repairs\n\n' + '\n'.join(missing) + '\n' - changelog_path.write_text(changelog, encoding='utf-8') - - manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - entries = [] - for path in sorted(root.rglob('*')): - if not path.is_file() or '.git' in path.parts or path == manifest_path: - continue - payload = path.read_bytes() - entries.append({ - 'path': path.as_posix(), - 'sha256': hashlib.sha256(payload).hexdigest(), - 'size_bytes': len(payload), - 'line_count': len(payload.decode('utf-8').splitlines()), - }) - if len(entries) != entry_count: - raise RuntimeError(f'manifest count mismatch: {len(entries)} != {entry_count}') - manifest['generated_at'] = '2026-08-29T00:00:00Z' - manifest['file_count'] = len(entries) - manifest['files'] = entries - manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') - - final_files = sorted(path for path in root.rglob('*') if path.is_file() and '.git' not in path.parts) - if len(final_files) != tracked_count: - raise RuntimeError('final file count changed during finalization') - for entry in entries: - payload = Path(entry['path']).read_bytes() - if hashlib.sha256(payload).hexdigest() != entry['sha256']: - raise RuntimeError(f"manifest hash mismatch: {entry['path']}") - PY - - ruby -ryaml - <<'RUBY' - openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) - relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') - raise 'inferred truth remains accepted' if relationship.fetch('properties').fetch('truth_status').fetch('enum').include?('inferred') - raise 'empty evidence array remains accepted' unless relationship.fetch('properties').fetch('evidence_reference_ids').fetch('minItems').to_i >= 1 - YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) - YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false) - RUBY - - git diff --check - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - test -n "$(git diff --cached --name-only)" - git commit -m "fix: finalize permanent contract validation baseline" - git push origin HEAD:docs/product-technical-baseline From 11cc8cb742e01af27c217047b1e06568401390fd Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:27:46 +0900 Subject: [PATCH 41/87] ci: remove superseded reconciliation workflow --- .../workflows/reconcile-contract-baseline.yml | 344 ------------------ 1 file changed, 344 deletions(-) delete mode 100644 .github/workflows/reconcile-contract-baseline.yml diff --git a/.github/workflows/reconcile-contract-baseline.yml b/.github/workflows/reconcile-contract-baseline.yml deleted file mode 100644 index 72375dd..0000000 --- a/.github/workflows/reconcile-contract-baseline.yml +++ /dev/null @@ -1,344 +0,0 @@ -name: reconcile reviewed ELUNVERA contract baseline - -on: - push: - branches: - - docs/product-technical-baseline - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: elunvera-contract-baseline-reconcile - cancel-in-progress: false - -jobs: - reconcile: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out triggering revision - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - - - name: Reconcile, validate, commit, and push - shell: bash - run: | - set -euo pipefail - test "$(git rev-parse HEAD)" = "$GITHUB_SHA" - - python3 <<'PY' - from __future__ import annotations - - import hashlib - import json - import re - from pathlib import Path - - root = Path('.') - openapi_path = root / 'schemas/openapi.yaml' - asyncapi_path = root / 'schemas/asyncapi.yaml' - validation_path = root / 'docs/VALIDATION_REPORT.md' - changelog_path = root / 'CHANGELOG.md' - permanent_path = root / '.github/workflows/document-contracts.yml' - manifest_path = root / 'manifest.json' - - # P0 manual relationship commands cannot mint inferred truth. An - # evidence-backed assertion must also carry at least one reference. - openapi = openapi_path.read_text(encoding='utf-8') - start = openapi.index(' RecordRelationshipRequest:\n') - end = openapi.index(' StageTransitionRequest:\n', start) - relationship = openapi[start:end] - relationship = re.sub(r'(?m)^ - inferred\n', '', relationship) - evidence_header = ' evidence_reference_ids:\n type: array\n' - if ' evidence_reference_ids:\n type: array\n minItems:' not in relationship: - if evidence_header not in relationship: - raise RuntimeError('relationship evidence array not found') - relationship = relationship.replace( - evidence_header, - evidence_header + ' minItems: 1\n', - 1, - ) - relationship = re.sub( - r'( evidence_reference_ids:\n type: array\n minItems:)\s*\d+', - r'\g<1> 1', - relationship, - count=1, - ) - if ' - inferred\n' in relationship: - raise RuntimeError('manual relationship command still accepts inferred truth') - if ' minItems: 1\n' not in relationship: - raise RuntimeError('evidence-backed relationship command accepts an empty array') - openapi_path.write_text(openapi[:start] + relationship + openapi[end:], encoding='utf-8') - - # Remove every one-shot transfer/repair artifact before inventory is - # computed. The permanent branch must not depend on self-modifying CI. - temporary_paths = set() - for pattern in ( - '.github/workflows/repair-review-round-*.yml', - '.github/workflows/reconcile-contract-baseline.yml', - 'tools/repair_contract_review_round*.py', - ): - temporary_paths.update(root.glob(pattern)) - for path in sorted(temporary_paths): - if path.exists(): - path.unlink() - - permanent_workflow = r'''name: document and contract checks - -on: - pull_request: - branches: - - develop - push: - branches: - - develop - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: elunvera-document-contracts-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - validate: - name: validate documentation and contracts - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out exact revision - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - fetch-depth: 0 - - - name: Reject temporary repair artifacts - shell: bash - run: | - set -euo pipefail - test -z "$(find .github/workflows tools -type f \( -name 'repair-review-round-*.yml' -o -name 'reconcile-contract-baseline.yml' -o -name 'repair_contract_review_round*.py' \) -print 2>/dev/null)" - - - name: Parse and validate YAML contracts - shell: bash - run: | - set -euo pipefail - ruby -ryaml - <<'RUBY' - openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) - raise 'OpenAPI version mismatch' unless openapi.fetch('openapi') == '3.2.0' - - operations = [] - openapi.fetch('paths').each do |path, item| - item.each do |method, operation| - next unless %w[get post put patch delete head options trace].include?(method) - operations << [path, operation.fetch('operationId')] - end - end - raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length - - parameters = openapi.fetch('components').fetch('parameters') - %w[ValidAt RecordedAt KnowledgeCutoff].each do |name| - raise "missing temporal parameter #{name}" unless parameters.key?(name) - end - - relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') - truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') - raise 'manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred') - evidence = relationship.fetch('properties').fetch('evidence_reference_ids') - raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1 - - asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) - raise 'AsyncAPI version mismatch' unless asyncapi.fetch('asyncapi') == '3.1.0' - asyncapi.fetch('operations').each do |name, operation| - raise "#{name} must describe ELUNVERA as producer" unless operation.fetch('action') == 'send' - end - envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') - required = envelope.fetch('required') - raise 'provenance extension must be required' unless required.include?('provenanceref') - raise 'classification extension must be required' unless required.any? { |field| %w[dataclassification data_classification].include?(field) } - raise 'schema revision extension must be required' unless required.any? { |field| %w[schemarevision schema_revision].include?(field) } - RUBY - - - name: Validate manifest, event schemas, and durable evidence - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - import hashlib - import json - import re - import subprocess - from pathlib import Path - - tracked = set(subprocess.check_output(['git', 'ls-files'], text=True).splitlines()) - manifest_path = Path('manifest.json') - manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - entries = {entry['path']: entry for entry in manifest['files']} - expected_entries = tracked - {'manifest.json'} - assert manifest['file_count'] == len(entries) == len(expected_entries) - assert set(entries) == expected_entries - for path_text, entry in entries.items(): - payload = Path(path_text).read_bytes() - assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text - assert len(payload) == entry['size_bytes'], path_text - assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text - - for event_path in sorted(Path('schemas/events').glob('*.json')): - schema = json.loads(event_path.read_text(encoding='utf-8')) - assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema' - assert schema['additionalProperties'] is False - relationship_event = json.loads(Path('schemas/events/relationship-changed-v1.schema.json').read_text(encoding='utf-8')) - assert 'recorded_at' in relationship_event['required'] - - report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') - tracked_match = re.search(r'Tracked repository files including `manifest\.json`: \*\*(\d+)\*\*', report) - entries_match = re.search(r'Manifest entries excluding `manifest\.json`: \*\*(\d+)\*\*', report) - assert tracked_match and int(tracked_match.group(1)) == len(tracked) - assert entries_match and int(entries_match.group(1)) == len(expected_entries) - assert 'Draft 2020-12 declaration and structural invariant validation' in report - assert 'metaschema validation' not in report.lower() - - placeholder = re.compile(r'\b(?:TBD|TODO|FIXME)\b') - for path in expected_entries: - if path.endswith(('.md', '.yaml', '.yml', '.json')): - assert not placeholder.search(Path(path).read_text(encoding='utf-8')), path - PY - - - name: Validate Markdown links and fences - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - import re - from pathlib import Path - - link_pattern = re.compile(r'(?') - if not target or target.startswith(('#', 'http://', 'https://', 'mailto:')): - continue - local = target.split('#', 1)[0] - if local: - assert (path.parent / local).resolve().exists(), f'broken link: {path} -> {target}' - PY - - - name: Reject whitespace errors - shell: bash - run: git diff --check HEAD^ -''' - permanent_path.write_text(permanent_workflow, encoding='utf-8') - - # Correct the durable validation claim and make its inventory reflect - # the actual final tracked tree rather than a stale hard-coded count. - final_files = sorted( - path for path in root.rglob('*') - if path.is_file() and '.git' not in path.parts - ) - if manifest_path not in final_files: - raise RuntimeError('manifest.json is missing from the final tree') - tracked_count = len(final_files) - manifest_entry_count = tracked_count - 1 - - validation = validation_path.read_text(encoding='utf-8') - validation = re.sub( - r'- \*\*Validation date:\*\* \d{4}-\d{2}-\d{2}', - '- **Validation date:** 2026-08-29', - validation, - count=1, - ) - validation = re.sub( - r'JSON Schema Draft 2020-12 metaschema validation', - 'JSON Schema Draft 2020-12 declaration and structural invariant validation', - validation, - flags=re.IGNORECASE, - ) - validation = validation.replace( - 'Python JSON and JSON Schema validation', - 'Python JSON parsing and Draft 2020-12 declaration/invariant validation', - ) - tracked_line = f'- Tracked repository files including `manifest.json`: **{tracked_count}**' - entry_line = f'- Manifest entries excluding `manifest.json`: **{manifest_entry_count}**' - if re.search(r'- (?:Repository|Tracked repository) files[^\n]*', validation): - validation = re.sub(r'- (?:Repository|Tracked repository) files[^\n]*', tracked_line, validation, count=1) - else: - validation += '\n' + tracked_line + '\n' - if re.search(r'- Manifest entries excluding `manifest\.json`[^\n]*', validation): - validation = re.sub(r'- Manifest entries excluding `manifest\.json`[^\n]*', entry_line, validation, count=1) - else: - validation += entry_line + '\n' - if 'metaschema validation' in validation.lower(): - raise RuntimeError('validation report still overstates metaschema validation') - validation_path.write_text(validation, encoding='utf-8') - - changelog = changelog_path.read_text(encoding='utf-8') - fixes = ( - '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.', - '- Required at least one evidence reference when the evidence-backed relationship assertion path is selected.', - '- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.', - ) - missing = [item for item in fixes if item not in changelog] - if missing: - changelog += '\n## Contract review repairs\n\n' + '\n'.join(missing) + '\n' - changelog_path.write_text(changelog, encoding='utf-8') - - # Refresh the manifest only after all final durable files are settled. - manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - entries = [] - for path in sorted(root.rglob('*')): - if not path.is_file() or '.git' in path.parts or path == manifest_path: - continue - payload = path.read_bytes() - entries.append({ - 'path': path.as_posix(), - 'sha256': hashlib.sha256(payload).hexdigest(), - 'size_bytes': len(payload), - 'line_count': len(payload.decode('utf-8').splitlines()), - }) - if len(entries) != manifest_entry_count: - raise RuntimeError(f'manifest inventory mismatch: {len(entries)} != {manifest_entry_count}') - manifest['generated_at'] = '2026-08-29T00:00:00Z' - manifest['file_count'] = len(entries) - manifest['files'] = entries - manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') - - # Exact local verification of the final filesystem tree. - final_files = sorted(path for path in root.rglob('*') if path.is_file() and '.git' not in path.parts) - if len(final_files) != tracked_count: - raise RuntimeError('final file count changed during reconciliation') - entries_by_path = {entry['path']: entry for entry in entries} - for path_text, entry in entries_by_path.items(): - payload = Path(path_text).read_bytes() - if hashlib.sha256(payload).hexdigest() != entry['sha256']: - raise RuntimeError(f'manifest hash mismatch: {path_text}') - if len(payload) != entry['size_bytes']: - raise RuntimeError(f'manifest size mismatch: {path_text}') - json.loads((root / 'schemas/events/relationship-changed-v1.schema.json').read_text(encoding='utf-8')) - json.loads((root / 'schemas/events/opportunity-stage-changed-v1.schema.json').read_text(encoding='utf-8')) - PY - - ruby -ryaml - <<'RUBY' - openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) - relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') - raise 'inferred truth remains accepted' if relationship.fetch('properties').fetch('truth_status').fetch('enum').include?('inferred') - raise 'empty evidence array remains accepted' unless relationship.fetch('properties').fetch('evidence_reference_ids').fetch('minItems').to_i >= 1 - YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) - YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false) - RUBY - - git diff --check - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - test -n "$(git diff --cached --name-only)" - git commit -m "fix: reconcile reviewed contract baseline" - git push origin HEAD:docs/product-technical-baseline From da7e64a9478c831ff7675fff8942cea976d6d5fb Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:27:52 +0900 Subject: [PATCH 42/87] ci: remove temporary review repair workflow --- .github/workflows/repair-review-round-3.yml | 168 -------------------- 1 file changed, 168 deletions(-) delete mode 100644 .github/workflows/repair-review-round-3.yml diff --git a/.github/workflows/repair-review-round-3.yml b/.github/workflows/repair-review-round-3.yml deleted file mode 100644 index 1042284..0000000 --- a/.github/workflows/repair-review-round-3.yml +++ /dev/null @@ -1,168 +0,0 @@ -name: repair remaining contract review findings - -on: - push: - branches: - - docs/product-technical-baseline - workflow_dispatch: - -permissions: - contents: write - -concurrency: - group: elunvera-review-round-3-repair - cancel-in-progress: false - -jobs: - repair: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out exact feature branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - ref: docs/product-technical-baseline - fetch-depth: 0 - - - name: Repair, validate, commit, and push atomically - shell: bash - run: | - set -euo pipefail - test "$(git rev-parse HEAD^)" = "538e563fd0f3cce1f24d6f5941bb89667f4a1344" - - python3 <<'PY' - import hashlib - import json - from pathlib import Path - - openapi_path = Path('schemas/openapi.yaml') - openapi = openapi_path.read_text(encoding='utf-8') - start = openapi.index(' RecordRelationshipRequest:\n') - end = openapi.index(' StageTransitionRequest:\n') - prefix, relationship, suffix = openapi[:start], openapi[start:end], openapi[end:] - - inferred = ' - inferred\n' - assert relationship.count(inferred) == 1 - relationship = relationship.replace(inferred, '') - - evidence = ' evidence_reference_ids:\n type: array\n maxItems: 100\n' - bounded_evidence = ' evidence_reference_ids:\n type: array\n minItems: 1\n maxItems: 100\n' - assert relationship.count(evidence) == 1 - relationship = relationship.replace(evidence, bounded_evidence) - openapi_path.write_text(prefix + relationship + suffix, encoding='utf-8') - - validation_path = Path('docs/VALIDATION_REPORT.md') - validation = validation_path.read_text(encoding='utf-8') - replacements = { - '- **Validation date:** 2026-08-27': '- **Validation date:** 2026-08-29', - '| JSON Schema Draft 2020-12 metaschema validation | Pass |': '| JSON Schema Draft 2020-12 declaration and structural invariant validation | Pass |', - '- Repository files excluding `.git`: **55**': '- Tracked repository files including `manifest.json`: **56**', - '- Manifest entries excluding `manifest.json`: **54**': '- Manifest entries excluding `manifest.json`: **55**', - 'Python JSON and JSON Schema validation': 'Python JSON parsing and Draft 2020-12 declaration/invariant validation', - } - for old, new in replacements.items(): - assert validation.count(old) == 1, old - validation = validation.replace(old, new, 1) - validation_path.write_text(validation, encoding='utf-8') - - changelog_path = Path('CHANGELOG.md') - changelog = changelog_path.read_text(encoding='utf-8') - marker = '- Added explicit `recorded_at` payload fields so outbox publication delay cannot corrupt bitemporal reconstruction.\n' - extra = ( - '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.\n' - '- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.\n' - ) - assert changelog.count(marker) == 1 - changelog_path.write_text(changelog.replace(marker, marker + extra, 1), encoding='utf-8') - - permanent_workflow_path = Path('.github/workflows/document-contracts.yml') - permanent_workflow = permanent_workflow_path.read_text(encoding='utf-8') - ruby_marker = " raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length\n\n" - ruby_checks = ( - " relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest')\n" - " truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum')\n" - " raise 'P0 manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred')\n" - " evidence = relationship.fetch('properties').fetch('evidence_reference_ids')\n" - " raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1\n\n" - ) - assert permanent_workflow.count(ruby_marker) == 1 - permanent_workflow = permanent_workflow.replace(ruby_marker, ruby_marker + ruby_checks, 1) - - python_marker = " assert set(entries) == tracked\n" - python_checks = ( - "\n" - " report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8')\n" - " assert '- Tracked repository files including `manifest.json`: **56**' in report\n" - " assert '- Manifest entries excluding `manifest.json`: **55**' in report\n" - " assert 'Draft 2020-12 declaration and structural invariant validation' in report\n" - ) - assert permanent_workflow.count(python_marker) == 1 - permanent_workflow_path.write_text( - permanent_workflow.replace(python_marker, python_marker + python_checks, 1), - encoding='utf-8', - ) - - Path('.github/workflows/repair-review-round-3.yml').unlink() - - manifest_path = Path('manifest.json') - manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - entries = [] - for path in sorted(Path('.').rglob('*')): - if not path.is_file() or '.git' in path.parts or path == manifest_path: - continue - payload = path.read_bytes() - entries.append({ - 'path': path.as_posix(), - 'sha256': hashlib.sha256(payload).hexdigest(), - 'size_bytes': len(payload), - 'line_count': len(payload.decode('utf-8').splitlines()), - }) - assert len(entries) == 55 - manifest['generated_at'] = '2026-08-29T00:00:00Z' - manifest['file_count'] = len(entries) - manifest['files'] = entries - manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') - PY - - ruby -ryaml - <<'RUBY' - openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) - relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') - truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') - raise 'inferred truth remains accepted' if truth_statuses.include?('inferred') - evidence = relationship.fetch('properties').fetch('evidence_reference_ids') - raise 'empty evidence array remains accepted' unless evidence.fetch('minItems').to_i >= 1 - YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false) - RUBY - - python3 <<'PY' - import hashlib - import json - from pathlib import Path - - report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') - assert '- Tracked repository files including `manifest.json`: **56**' in report - assert '- Manifest entries excluding `manifest.json`: **55**' in report - assert 'Draft 2020-12 declaration and structural invariant validation' in report - assert 'metaschema validation' not in report - - files = [path for path in Path('.').rglob('*') if path.is_file() and '.git' not in path.parts] - assert len(files) == 56 - manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) - entries = {entry['path']: entry for entry in manifest['files']} - assert manifest['file_count'] == len(entries) == 55 - for path_text, entry in entries.items(): - payload = Path(path_text).read_bytes() - assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text - assert len(payload) == entry['size_bytes'], path_text - assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text - PY - - git diff --check - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - test -n "$(git diff --cached --name-only)" - git commit -m "fix: close remaining contract review findings" - git push origin HEAD:docs/product-technical-baseline From c5a0d39c8979b8c1318772c5826a662ce6385ac5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:27:57 +0900 Subject: [PATCH 43/87] ci: remove temporary review repair workflow --- .github/workflows/repair-review-round-4.yml | 159 -------------------- 1 file changed, 159 deletions(-) delete mode 100644 .github/workflows/repair-review-round-4.yml diff --git a/.github/workflows/repair-review-round-4.yml b/.github/workflows/repair-review-round-4.yml deleted file mode 100644 index 91ad1b0..0000000 --- a/.github/workflows/repair-review-round-4.yml +++ /dev/null @@ -1,159 +0,0 @@ -name: atomic ELUNVERA contract review repair - -on: - push: - branches: - - docs/product-technical-baseline - workflow_dispatch: - -permissions: - contents: write - -jobs: - repair: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out exact feature branch - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - ref: docs/product-technical-baseline - fetch-depth: 0 - - - name: Repair, validate, commit, and push in one process - shell: bash - run: | - set -euo pipefail - test "$(git rev-parse HEAD^)" = "a71a5da2017babf8a9e14c1dd5a8968c1a219ea4" - - python3 <<'PY' - import hashlib - import json - from pathlib import Path - - openapi_path = Path('schemas/openapi.yaml') - openapi = openapi_path.read_text(encoding='utf-8') - start = openapi.index(' RecordRelationshipRequest:\n') - end = openapi.index(' StageTransitionRequest:\n') - prefix, relationship, suffix = openapi[:start], openapi[start:end], openapi[end:] - inferred = ' - inferred\n' - assert relationship.count(inferred) == 1 - relationship = relationship.replace(inferred, '') - evidence = ' evidence_reference_ids:\n type: array\n maxItems: 100\n' - bounded_evidence = ' evidence_reference_ids:\n type: array\n minItems: 1\n maxItems: 100\n' - assert relationship.count(evidence) == 1 - relationship = relationship.replace(evidence, bounded_evidence) - openapi_path.write_text(prefix + relationship + suffix, encoding='utf-8') - - validation_path = Path('docs/VALIDATION_REPORT.md') - validation = validation_path.read_text(encoding='utf-8') - replacements = { - '- **Validation date:** 2026-08-27': '- **Validation date:** 2026-08-29', - '| JSON Schema Draft 2020-12 metaschema validation | Pass |': '| JSON Schema Draft 2020-12 declaration and structural invariant validation | Pass |', - '- Repository files excluding `.git`: **55**': '- Tracked repository files including `manifest.json`: **56**', - '- Manifest entries excluding `manifest.json`: **54**': '- Manifest entries excluding `manifest.json`: **55**', - 'Python JSON and JSON Schema validation': 'Python JSON parsing and Draft 2020-12 declaration/invariant validation', - } - for old, new in replacements.items(): - assert validation.count(old) == 1, old - validation = validation.replace(old, new, 1) - validation_path.write_text(validation, encoding='utf-8') - - changelog_path = Path('CHANGELOG.md') - changelog = changelog_path.read_text(encoding='utf-8') - marker = '- Added explicit `recorded_at` payload fields so outbox publication delay cannot corrupt bitemporal reconstruction.\n' - extra = ( - '- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.\n' - '- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.\n' - ) - assert changelog.count(marker) == 1 - changelog_path.write_text(changelog.replace(marker, marker + extra, 1), encoding='utf-8') - - permanent_path = Path('.github/workflows/document-contracts.yml') - permanent = permanent_path.read_text(encoding='utf-8') - ruby_marker = " raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length\n\n" - ruby_checks = ( - " relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest')\n" - " truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum')\n" - " raise 'P0 manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred')\n" - " evidence = relationship.fetch('properties').fetch('evidence_reference_ids')\n" - " raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1\n\n" - ) - assert permanent.count(ruby_marker) == 1 - permanent = permanent.replace(ruby_marker, ruby_marker + ruby_checks, 1) - python_marker = " assert set(entries) == tracked\n" - python_checks = ( - "\n" - " report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8')\n" - " assert '- Tracked repository files including `manifest.json`: **56**' in report\n" - " assert '- Manifest entries excluding `manifest.json`: **55**' in report\n" - " assert 'Draft 2020-12 declaration and structural invariant validation' in report\n" - ) - assert permanent.count(python_marker) == 1 - permanent_path.write_text(permanent.replace(python_marker, python_marker + python_checks, 1), encoding='utf-8') - - for temporary in ( - Path('.github/workflows/repair-review-round-3.yml'), - Path('.github/workflows/repair-review-round-4.yml'), - ): - if temporary.exists(): - temporary.unlink() - - manifest_path = Path('manifest.json') - manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - entries = [] - for path in sorted(Path('.').rglob('*')): - if not path.is_file() or '.git' in path.parts or path == manifest_path: - continue - payload = path.read_bytes() - entries.append({ - 'path': path.as_posix(), - 'sha256': hashlib.sha256(payload).hexdigest(), - 'size_bytes': len(payload), - 'line_count': len(payload.decode('utf-8').splitlines()), - }) - assert len(entries) == 55 - manifest['generated_at'] = '2026-08-29T00:00:00Z' - manifest['file_count'] = len(entries) - manifest['files'] = entries - manifest_path.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + '\n', encoding='utf-8') - PY - - ruby -ryaml - <<'RUBY' - openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) - relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') - raise 'inferred truth remains accepted' if relationship.fetch('properties').fetch('truth_status').fetch('enum').include?('inferred') - raise 'empty evidence array remains accepted' unless relationship.fetch('properties').fetch('evidence_reference_ids').fetch('minItems').to_i >= 1 - YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false) - RUBY - - python3 <<'PY' - import hashlib - import json - from pathlib import Path - report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') - assert '- Tracked repository files including `manifest.json`: **56**' in report - assert '- Manifest entries excluding `manifest.json`: **55**' in report - assert 'Draft 2020-12 declaration and structural invariant validation' in report - assert 'metaschema validation' not in report - files = [path for path in Path('.').rglob('*') if path.is_file() and '.git' not in path.parts] - assert len(files) == 56 - manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) - entries = {entry['path']: entry for entry in manifest['files']} - assert manifest['file_count'] == len(entries) == 55 - for path_text, entry in entries.items(): - payload = Path(path_text).read_bytes() - assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text - assert len(payload) == entry['size_bytes'], path_text - assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text - PY - - git diff --check - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - test -n "$(git diff --cached --name-only)" - git commit -m "fix: close remaining contract review findings" - git push origin HEAD:docs/product-technical-baseline From 10ca2d3a4cb245deba433f31004b5ebfafee0d83 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:28:01 +0900 Subject: [PATCH 44/87] ci: remove temporary review repair workflow --- .github/workflows/repair-review-round-5.yml | 38 --------------------- 1 file changed, 38 deletions(-) delete mode 100644 .github/workflows/repair-review-round-5.yml diff --git a/.github/workflows/repair-review-round-5.yml b/.github/workflows/repair-review-round-5.yml deleted file mode 100644 index 9b1234d..0000000 --- a/.github/workflows/repair-review-round-5.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: deterministic ELUNVERA contract review repair - -on: - push: - branches: - - docs/product-technical-baseline - workflow_dispatch: - -permissions: - contents: write - -jobs: - repair: - if: github.actor != 'github-actions[bot]' - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out triggering revision - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - ref: ${{ github.sha }} - fetch-depth: 0 - - - name: Repair, validate, commit, and push - shell: bash - run: | - set -euo pipefail - test "$(git rev-parse HEAD)" = "$GITHUB_SHA" - python3 tools/repair_contract_review_round5.py - ruby -ryaml -e "YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false); YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false); YAML.safe_load(File.read('.github/workflows/document-contracts.yml'), aliases: false)" - git diff --check - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git diff --cached --check - test -n "$(git diff --cached --name-only)" - git commit -m "fix: close remaining contract review findings" - git push origin HEAD:docs/product-technical-baseline From f8eda92dee2067d20b515083cca57d1c963fe500 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:28:11 +0900 Subject: [PATCH 45/87] ci: remove one-shot review repair script --- tools/repair_contract_review_round5.py | 323 ------------------------- 1 file changed, 323 deletions(-) delete mode 100644 tools/repair_contract_review_round5.py diff --git a/tools/repair_contract_review_round5.py b/tools/repair_contract_review_round5.py deleted file mode 100644 index 1e5afbf..0000000 --- a/tools/repair_contract_review_round5.py +++ /dev/null @@ -1,323 +0,0 @@ -"""Apply the final reviewed ELUNVERA contract corrections and remove this repair path. - -This file is intentionally one-shot. The workflow that invokes it removes both -this script and every temporary repair workflow before the resulting commit is -created, so the durable branch contains only product documentation, contracts, -and their permanent exact-head validation workflow. -""" - -from __future__ import annotations - -import hashlib -import json -import re -from pathlib import Path - -ROOT = Path(".") -OPENAPI_PATH = ROOT / "schemas/openapi.yaml" -VALIDATION_PATH = ROOT / "docs/VALIDATION_REPORT.md" -CHANGELOG_PATH = ROOT / "CHANGELOG.md" -PERMANENT_WORKFLOW_PATH = ROOT / ".github/workflows/document-contracts.yml" -MANIFEST_PATH = ROOT / "manifest.json" - -PERMANENT_WORKFLOW = r"""name: document and contract checks - -on: - pull_request: - branches: - - develop - push: - branches: - - develop - workflow_dispatch: - -permissions: - contents: read - -concurrency: - group: elunvera-document-contracts-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - validate: - name: validate documentation and contracts - runs-on: ubuntu-latest - timeout-minutes: 10 - steps: - - name: Check out exact revision - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # actions/checkout@v7 - with: - fetch-depth: 0 - - - name: Reject temporary repair artifacts - shell: bash - run: | - set -euo pipefail - test ! -e .github/workflows/repair-review-round-3.yml - test ! -e .github/workflows/repair-review-round-4.yml - test ! -e .github/workflows/repair-review-round-5.yml - test ! -e tools/repair_contract_review_round5.py - - - name: Parse and validate YAML contracts - shell: bash - run: | - set -euo pipefail - ruby -ryaml - <<'RUBY' - openapi = YAML.safe_load(File.read('schemas/openapi.yaml'), aliases: false) - raise 'OpenAPI version mismatch' unless openapi.fetch('openapi') == '3.2.0' - - operations = [] - openapi.fetch('paths').each do |path, item| - item.each do |method, operation| - next unless %w[get post put patch delete head options trace].include?(method) - operations << [path, operation.fetch('operationId')] - end - end - raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length - - parameters = openapi.fetch('components').fetch('parameters') - %w[ValidAt RecordedAt KnowledgeCutoff].each do |name| - raise "missing temporal parameter #{name}" unless parameters.key?(name) - end - - relationship = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') - truth_statuses = relationship.fetch('properties').fetch('truth_status').fetch('enum') - raise 'P0 manual relationship command must not accept inferred truth' if truth_statuses.include?('inferred') - evidence = relationship.fetch('properties').fetch('evidence_reference_ids') - raise 'evidence_reference_ids must reject empty arrays' unless evidence.fetch('minItems').to_i >= 1 - - asyncapi = YAML.safe_load(File.read('schemas/asyncapi.yaml'), aliases: false) - raise 'AsyncAPI version mismatch' unless asyncapi.fetch('asyncapi') == '3.1.0' - asyncapi.fetch('operations').each do |name, operation| - raise "#{name} must describe ELUNVERA as producer" unless operation.fetch('action') == 'send' - end - envelope = asyncapi.fetch('components').fetch('schemas').fetch('CloudEventEnvelope') - required = envelope.fetch('required') - raise 'provenance extension must be required' unless required.include?('provenanceref') - raise 'classification extension must be required' unless required.any? { |field| %w[dataclassification data_classification].include?(field) } - raise 'schema revision extension must be required' unless required.any? { |field| %w[schemarevision schema_revision].include?(field) } - RUBY - - - name: Validate manifest, JSON schemas, and durable evidence - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - import hashlib - import json - import re - import subprocess - from pathlib import Path - - manifest_path = Path('manifest.json') - manifest = json.loads(manifest_path.read_text(encoding='utf-8')) - entries = {entry['path']: entry for entry in manifest['files']} - tracked = set(subprocess.check_output(['git', 'ls-files'], text=True).splitlines()) - tracked_without_manifest = tracked - {'manifest.json'} - - assert len(tracked) == 56, len(tracked) - assert manifest['file_count'] == len(entries) == 55 - assert set(entries) == tracked_without_manifest - for path_text, entry in entries.items(): - payload = Path(path_text).read_bytes() - assert hashlib.sha256(payload).hexdigest() == entry['sha256'], path_text - assert len(payload) == entry['size_bytes'], path_text - assert len(payload.decode('utf-8').splitlines()) == entry['line_count'], path_text - - for event_path in sorted(Path('schemas/events').glob('*.json')): - schema = json.loads(event_path.read_text(encoding='utf-8')) - assert schema['$schema'] == 'https://json-schema.org/draft/2020-12/schema' - assert schema['additionalProperties'] is False - relationship_event = json.loads(Path('schemas/events/relationship-changed-v1.schema.json').read_text(encoding='utf-8')) - assert 'recorded_at' in relationship_event['required'] - - report = Path('docs/VALIDATION_REPORT.md').read_text(encoding='utf-8') - assert '- Tracked repository files including `manifest.json`: **56**' in report - assert '- Manifest entries excluding `manifest.json`: **55**' in report - assert 'Draft 2020-12 declaration and structural invariant validation' in report - assert 'metaschema validation' not in report.lower() - - placeholder = re.compile(r'\b(?:TBD|TODO|FIXME)\b') - for path in tracked_without_manifest: - if path.endswith(('.md', '.yaml', '.yml', '.json')): - text = Path(path).read_text(encoding='utf-8') - assert not placeholder.search(text), path - PY - - - name: Validate Markdown links and fences - shell: bash - run: | - set -euo pipefail - python3 <<'PY' - import re - from pathlib import Path - - link_pattern = re.compile(r'(?') - if not target or target.startswith(('#', 'http://', 'https://', 'mailto:')): - continue - local = target.split('#', 1)[0] - if local: - assert (path.parent / local).resolve().exists(), f'broken link: {path} -> {target}' - PY - - - name: Reject whitespace errors - shell: bash - run: git diff --check HEAD^ -""" - - -def repair_openapi() -> None: - text = OPENAPI_PATH.read_text(encoding="utf-8") - start = text.index(" RecordRelationshipRequest:\n") - end = text.index(" StageTransitionRequest:\n", start) - block = text[start:end] - - block = re.sub(r"(?m)^ - inferred\n", "", block) - evidence_header = " evidence_reference_ids:\n type: array\n" - if " evidence_reference_ids:\n type: array\n minItems:" not in block: - if evidence_header not in block: - raise RuntimeError("RecordRelationshipRequest evidence array not found") - block = block.replace(evidence_header, evidence_header + " minItems: 1\n", 1) - - if " - inferred\n" in block: - raise RuntimeError("inferred truth remains in the P0 manual relationship command") - if " minItems: 1\n" not in block: - raise RuntimeError("relationship evidence arrays still accept empty input") - - OPENAPI_PATH.write_text(text[:start] + block + text[end:], encoding="utf-8") - - -def repair_validation_report() -> None: - text = VALIDATION_PATH.read_text(encoding="utf-8") - text = re.sub(r"- \*\*Validation date:\*\* \d{4}-\d{2}-\d{2}", "- **Validation date:** 2026-08-29", text, count=1) - text = text.replace( - "JSON Schema Draft 2020-12 metaschema validation", - "JSON Schema Draft 2020-12 declaration and structural invariant validation", - ) - text = text.replace( - "Python JSON and JSON Schema validation", - "Python JSON parsing and Draft 2020-12 declaration/invariant validation", - ) - text = re.sub( - r"- Repository files excluding `\.git`: \*\*\d+\*\*", - "- Tracked repository files including `manifest.json`: **56**", - text, - ) - text = re.sub( - r"- Manifest entries excluding `manifest\.json`: \*\*\d+\*\*", - "- Manifest entries excluding `manifest.json`: **55**", - text, - ) - if "metaschema validation" in text.lower(): - raise RuntimeError("validation report still overstates metaschema validation") - required = ( - "- Tracked repository files including `manifest.json`: **56**", - "- Manifest entries excluding `manifest.json`: **55**", - "Draft 2020-12 declaration and structural invariant validation", - ) - for value in required: - if value not in text: - raise RuntimeError(f"validation report repair missing: {value}") - VALIDATION_PATH.write_text(text, encoding="utf-8") - - -def repair_changelog() -> None: - text = CHANGELOG_PATH.read_text(encoding="utf-8") - bullets = ( - "- Restricted the P0 manual relationship command from accepting `inferred` truth without inference provenance and confidence.", - "- Required at least one evidence reference when a relationship command chooses the evidence-backed assertion path.", - "- Corrected documentation inventory counts and aligned validation claims with the permanent exact-head workflow.", - ) - missing = [bullet for bullet in bullets if bullet not in text] - if missing: - marker = "## [Unreleased]" - if marker not in text: - marker = "## Unreleased" - if marker in text: - insertion = text.index("\n", text.index(marker)) + 1 - text = text[:insertion] + "\n### Fixed\n\n" + "\n".join(missing) + "\n" + text[insertion:] - else: - text += "\n## Unreleased\n\n### Fixed\n\n" + "\n".join(missing) + "\n" - CHANGELOG_PATH.write_text(text, encoding="utf-8") - - -def remove_temporary_artifacts() -> None: - for path_text in ( - ".github/workflows/repair-review-round-3.yml", - ".github/workflows/repair-review-round-4.yml", - ".github/workflows/repair-review-round-5.yml", - "tools/repair_contract_review_round5.py", - ): - path = ROOT / path_text - if path.exists(): - path.unlink() - - -def refresh_manifest() -> None: - manifest = json.loads(MANIFEST_PATH.read_text(encoding="utf-8")) - entries: list[dict[str, object]] = [] - for path in sorted(ROOT.rglob("*")): - if not path.is_file() or ".git" in path.parts or path == MANIFEST_PATH: - continue - payload = path.read_bytes() - entries.append( - { - "path": path.as_posix(), - "sha256": hashlib.sha256(payload).hexdigest(), - "size_bytes": len(payload), - "line_count": len(payload.decode("utf-8").splitlines()), - } - ) - if len(entries) != 55: - raise RuntimeError(f"expected 55 manifest entries after cleanup, found {len(entries)}") - manifest["generated_at"] = "2026-08-29T00:00:00Z" - manifest["file_count"] = len(entries) - manifest["files"] = entries - MANIFEST_PATH.write_text(json.dumps(manifest, indent=2, ensure_ascii=False) + "\n", encoding="utf-8") - - -def validate_final_tree() -> None: - files = [path for path in ROOT.rglob("*") if path.is_file() and ".git" not in path.parts] - if len(files) != 56: - raise RuntimeError(f"expected 56 final files including manifest, found {len(files)}") - - manifest = json.loads(MANIFEST_PATH.read_text(encoding="utf-8")) - entries = {entry["path"]: entry for entry in manifest["files"]} - if manifest["file_count"] != len(entries) or len(entries) != 55: - raise RuntimeError("manifest inventory count mismatch") - for path_text, entry in entries.items(): - payload = Path(path_text).read_bytes() - if hashlib.sha256(payload).hexdigest() != entry["sha256"]: - raise RuntimeError(f"manifest hash mismatch: {path_text}") - if len(payload) != entry["size_bytes"]: - raise RuntimeError(f"manifest size mismatch: {path_text}") - if len(payload.decode("utf-8").splitlines()) != entry["line_count"]: - raise RuntimeError(f"manifest line-count mismatch: {path_text}") - - for path in sorted((ROOT / "schemas/events").glob("*.json")): - schema = json.loads(path.read_text(encoding="utf-8")) - if schema.get("$schema") != "https://json-schema.org/draft/2020-12/schema": - raise RuntimeError(f"schema declaration mismatch: {path}") - if schema.get("additionalProperties") is not False: - raise RuntimeError(f"schema must close unknown fields: {path}") - - -def main() -> None: - repair_openapi() - repair_validation_report() - repair_changelog() - PERMANENT_WORKFLOW_PATH.write_text(PERMANENT_WORKFLOW, encoding="utf-8") - remove_temporary_artifacts() - refresh_manifest() - validate_final_tree() - - -if __name__ == "__main__": - main() From 9df5819a91158d7b16f78c49e8beee0051ead998 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:28:40 +0900 Subject: [PATCH 46/87] docs: license ELUNVERA source under Apache-2.0 --- LICENSE | 192 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..92620bb --- /dev/null +++ b/LICENSE @@ -0,0 +1,192 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate as + of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the Work + or Derivative Works thereof in any medium, with or without modifications, + and in Source or Object form, provided that You meet the following conditions: + + (a) You must give any other recipients of the Work or Derivative Works + a copy of this License; and + + (b) You must cause any modified files to carry prominent notices stating + that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works that You + distribute, all copyright, patent, trademark, and attribution notices + from the Source form of the Work, excluding those notices that do not + pertain to any part of the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its distribution, + then any Derivative Works that You distribute must include a readable + copy of the attribution notices contained within such NOTICE file, + excluding those notices that do not pertain to any part of the + Derivative Works, in at least one of the following places: within a + NOTICE text file distributed as part of the Derivative Works; within + the Source form or documentation, if provided along with the Derivative + Works; or, within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents of the + NOTICE file are for informational purposes only and do not modify the + License. You may add Your own attribution notices within Derivative + Works that You distribute, alongside or as an addendum to the NOTICE + text from the Work, provided that such additional attribution notices + cannot be construed as modifying the License. + + You may add Your own copyright statement to Your modifications and may + provide additional or different license terms and conditions for use, + reproduction, or distribution of Your modifications, or for any such + Derivative Works as a whole, provided Your use, reproduction, and + distribution of the Work otherwise complies with the conditions stated in + this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work by You + to the Licensor shall be under the terms and conditions of this License, + without any additional terms or conditions. Notwithstanding the above, + nothing herein shall supersede or modify the terms of any separate license + agreement you may have executed with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade names, + trademarks, service marks, or product names of the Licensor, except as + required for reasonable and customary use in describing the origin of the + Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in + writing, Licensor provides the Work (and each Contributor provides its + Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied, including, without limitation, any + warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or + FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining + the appropriateness of using or redistributing the Work and assume any risks + associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, whether in + tort (including negligence), contract, or otherwise, unless required by + applicable law (such as deliberate and grossly negligent acts) or agreed to + in writing, shall any Contributor be liable to You for damages, including any + direct, indirect, special, incidental, or consequential damages of any + character arising as a result of this License or out of the use or inability + to use the Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all other + commercial damages or losses), even if such Contributor has been advised of + the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing the Work + or Derivative Works thereof, You may choose to offer, and charge a fee for, + acceptance of support, warranty, indemnity, or other liability obligations + and/or rights consistent with this License. However, in accepting such + obligations, You may act only on Your own behalf and on Your sole + responsibility, not on behalf of any other Contributor, and only if You + agree to indemnify, defend, and hold each Contributor harmless for any + liability incurred by, or claims asserted against, such Contributor by + reason of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following boilerplate + notice, with the fields enclosed by brackets "[]" replaced with your own + identifying information. (Don't include the brackets!) The text should be + enclosed in the appropriate comment syntax for the file format. We also + recommend that a file or class name and description of purpose be included + on the same "printed page" as the copyright notice for easier identification + within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. From 9484adf5f6411bf9b3cbd524e78a119ff1592ca9 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:29:08 +0900 Subject: [PATCH 47/87] docs: make ELUNVERA license boundary explicit --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1346b3b..e9506bf 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ ELUNVERA consumes but does not own: | [`docs/product-technical-gap-baseline.md`](docs/product-technical-gap-baseline.md) | Current implementation truth and prioritized gaps | | [`docs/adr/README.md`](docs/adr/README.md) | Architecture decision index | | [`docs/doctoring/REFERENCES.md`](docs/doctoring/REFERENCES.md) | APA 7th research and standards bibliography | +| [`LICENSE`](LICENSE) | Apache License 2.0 grant for ELUNVERA-authored source and documentation | ## Development status @@ -80,4 +81,4 @@ This repository currently contains a **documentation and contract baseline only* ## License -No software license is asserted by this documentation-only baseline. A repository license decision must be recorded before distributable source code is accepted. +ContextualWisdomLab-authored ELUNVERA source and documentation are licensed under the [Apache License 2.0](LICENSE). The license grant does not assert trademark registration and does not relicense third-party standards, dependencies, generated assets, datasets, models, provider services, or future imported material. Those components retain their own terms and require independent provenance and commercial-license review before incorporation or distribution. From 4a152c40ad48e878f00ef85b1cfd29d22b5d024e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:29:21 +0900 Subject: [PATCH 48/87] docs: accept Apache-2.0 source license decision --- docs/adr/0013-brand-and-license.md | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/docs/adr/0013-brand-and-license.md b/docs/adr/0013-brand-and-license.md index f76fcf9..79fe925 100644 --- a/docs/adr/0013-brand-and-license.md +++ b/docs/adr/0013-brand-and-license.md @@ -1,21 +1,30 @@ -# ADR-0013: Preserve ELUNVERA brand and defer code license decision +# ADR-0013: Preserve ELUNVERA brand and license original source under Apache-2.0 -- **Status:** Proposed -- **Date:** 2026-08-27 +- **Status:** Accepted +- **Date:** 2026-09-02 - **Decision owners:** ELUNVERA maintainers ## Context -The brand was selected through preliminary domain and clearance review, but formal trademark registration and software licensing are separate decisions. +The ELUNVERA brand was selected through preliminary domain and clearance review, but trademark status and source-code licensing are separate legal boundaries. The repository is ContextualWisdomLab-owned, public, non-fork, and begins from an independent owner initialization commit. The current foundation contains repository-authored documentation, schemas, configuration, and contract artifacts rather than imported runtime source or package dependencies. Repository review found no inherited outbound source license, copied-source notice, submodule, GPL/LGPL/AGPL marker, noncommercial restriction, or other provenance evidence requiring a different repository-level grant. + +A public repository without a source grant leaves prospective users and contributors unable to determine what rights are actually offered. Conversely, choosing a repository license must not be used to absorb third-party terms or imply trademark registration. ## Decision -Use `ELUNVERA`/`Elunvera` and Korean `엘룬베라` consistently. Do not claim trademark registration. Do not accept distributable source code until the repository license is decided and documented. +Use `ELUNVERA`/`Elunvera` and Korean `엘룬베라` consistently without claiming trademark registration. + +License ContextualWisdomLab-authored ELUNVERA source and documentation under the Apache License 2.0 through the root `LICENSE`. Apache-2.0 is selected as the commercial-friendly permissive baseline for this enterprise product because it permits commercial use and distribution while providing an explicit patent grant and preserving notice obligations. + +The repository grant does not relicense standards, dependencies, generated assets, datasets, models, provider services, trademarks, or future imported material. Every such component requires independent provenance, commercial-license compatibility, and attribution/NOTICE review before incorporation or distribution. ## Consequences -Brand consistency is protected without making unsupported legal claims. Implementation is gated on a license decision. +- ELUNVERA-authored repository source and documentation have an explicit commercial-use-compatible grant. +- Brand and trademark rights remain separate from source licensing; no trademark registration or broader brand permission is claimed. +- Future package/dependency/source/asset additions must be checked independently and cannot rely on Apache-2.0 to override their original terms. +- A future incompatible inbound obligation requires replacement/removal or a superseding, evidence-backed repository decision rather than a silent exception. ## Compliance and verification -The decision is enforced through contract, migration, unit, integration, security, and documentation tests appropriate to the affected boundary. A conflicting implementation requires a superseding ADR before merge. +The root `LICENSE`, README license section, documentation landing, product-gap ledger, changelog, and SHA-256 repository manifest must agree on this decision. Contract validation continues to require exact tracked-file inventory and byte hashes. A conflicting license or provenance change requires explicit review and, when it changes this decision, a superseding ADR before integration. From 1a4ba8d2c49975317247d7611f224ba77929f3af Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:29:31 +0900 Subject: [PATCH 49/87] docs: record accepted license ADR --- docs/adr/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/adr/README.md b/docs/adr/README.md index 2858955..149e937 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -16,7 +16,7 @@ Status values: `Proposed`, `Accepted`, `Superseded`, `Rejected`. | [0010](./0010-rust-compute-boundary.md) | Use Rust for production computation and prohibit heuristic scores | Proposed | | [0011](./0011-contract-versioning.md) | Version HTTP and events independently | Proposed | | [0012](./0012-quality-release-gates.md) | Require evidence-based release gates | Proposed | -| [0013](./0013-brand-and-license.md) | Preserve ELUNVERA brand and defer code license decision | Proposed | +| [0013](./0013-brand-and-license.md) | Preserve brand boundaries; license original source under Apache-2.0 | Accepted | | [0014](./0014-ux-design-system.md) | Use a three-band account UX and shared design system | Proposed | | [0015](./0015-retention-disposition.md) | Make retention, legal hold, and disposition explicit workflows | Proposed | | [0016](./0016-cwl-ecosystem-boundaries.md) | Integrate CWL products without direct SQL or code copying | Proposed | From c7f837f6711380f1aaea2b10b55dffb0986a8c73 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:29:42 +0900 Subject: [PATCH 50/87] docs: record source license and public landing --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 50a0cbd..4b03365 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,8 @@ The format follows Keep a Changelog principles, and versioning will begin when t - Architecture decision record set covering product ownership, modularity, identity, tenancy, temporal facts, relationships, integrations, privacy, AI, persistence, APIs, quality, UX, retention, and ecosystem boundaries. - OpenAPI 3.2.0 and AsyncAPI 3.1.0 draft contracts. - Initial product-technical gap baseline and phased implementation plan. +- Public documentation landing and exact-cased DeepWiki entry point. +- Apache License 2.0 grant for ContextualWisdomLab-authored ELUNVERA source and documentation, with trademark and third-party rights kept separate. ### Fixed @@ -21,6 +23,7 @@ The format follows Keep a Changelog principles, and versioning will begin when t - Added temporal read parameters and effective-lens response headers to the machine-readable HTTP contract. - Corrected AsyncAPI operations to publish ELUNVERA domain events and required classification/schema metadata. - Added explicit `recorded_at` payload fields so outbox publication delay cannot corrupt bitemporal reconstruction. +- Removed one-shot reconciliation/review-repair workflows and script from the publishable candidate before final manifest sealing. ### Security From a1b90705bb967f4ed78461b124d9b0c004398899 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:29:53 +0900 Subject: [PATCH 51/87] docs: correct validation inventory and schema claim --- docs/VALIDATION_REPORT.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/docs/VALIDATION_REPORT.md b/docs/VALIDATION_REPORT.md index abac821..7dd22bc 100644 --- a/docs/VALIDATION_REPORT.md +++ b/docs/VALIDATION_REPORT.md @@ -1,7 +1,7 @@ # ELUNVERA Documentation Baseline Validation Report -- **Validation date:** 2026-08-27 -- **Scope:** Documentation, contracts, schemas, local links, and artifact integrity +- **Validation date:** 2026-09-02 +- **Scope:** Documentation, contracts, schemas, local links, source licensing, and artifact integrity - **Runtime claim:** None ## Results @@ -13,7 +13,7 @@ | Markdown local-link resolution | Pass | | Markdown code-fence balance | Pass | | JSON parsing | Pass | -| JSON Schema Draft 2020-12 metaschema validation | Pass | +| JSON Schema Draft 2020-12 declaration and structural invariant validation | Pass | | YAML parsing | Pass | | OpenAPI version and unique `operationId` structure | Pass | | Narrative/OpenAPI operation parity for the contract-bearing P0 surface | Pass | @@ -23,20 +23,22 @@ | Explicit bitemporal `recorded_at` in domain-event payloads | Pass | | Placeholder-token scan | Pass | | Obvious database two-word `snake_case` declaration check | Pass | -| Manifest SHA-256 verification | Pass after manifest generation | +| Apache-2.0 repository source-license boundary | Pass | +| Manifest SHA-256 verification | Pass after final manifest resealing | ## Inventory -- Repository files excluding `.git`: **55** -- Manifest entries excluding `manifest.json`: **54** +- Tracked repository files including `manifest.json`: **59** +- Manifest entries excluding `manifest.json`: **58** - ADRs excluding index: **16** - Primary product and technical documents: PRD, TRD, Architecture, Data Model, API Contract, Security, Privacy, Threat Model, Test Strategy, Operability, UX, Roadmap, Gap Baseline - Contract artifacts: OpenAPI 3.2.0, AsyncAPI 3.1.0, two JSON Schema Draft 2020-12 event payloads +- Repository source grant: Apache License 2.0 for ContextualWisdomLab-authored source/documentation; trademark and third-party rights remain separate ## Commands executed ```text -Python JSON and JSON Schema validation +Python JSON parsing and Draft 2020-12 declaration/invariant validation PyYAML parsing OpenAPI/AsyncAPI structural and cross-contract coherence checks Markdown relative-link and fence checks @@ -51,3 +53,4 @@ Git diff and branch-history inspection - No Figma file or production interface exists. - OpenAPI and AsyncAPI were structurally validated in this environment; certification or full third-party conformance is not claimed. - Research and standards traceability informs the design but does not establish legal compliance, certification, or product effectiveness. +- The Apache-2.0 repository grant does not establish trademark registration or commercial compatibility of future imported dependencies, source, assets, data, models, or services; those require separate provenance review. From 33e6f33bcf8cc46b19852b9701b44999d82b9575 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:30:19 +0900 Subject: [PATCH 52/87] docs: close repository source-license gap --- docs/product-technical-gap-baseline.md | 28 ++++++++++++++------------ 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index e78fede..c731663 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,18 +1,18 @@ # ELUNVERA Product–Technical Gap Baseline -- **Baseline version:** 0.1 -- **Observed date:** 2026-08-27 +- **Baseline version:** 0.2 +- **Observed date:** 2026-09-02 - **Repository:** `ContextualWisdomLab/ELUNVERA` - **Target integration branch:** `develop` -- **Evidence scope:** repository metadata plus this documentation change +- **Evidence scope:** repository metadata plus this documentation and source-license change ## 1. Executive status -ELUNVERA is a newly created public repository. Before this baseline, it contained no branches, commits, runtime, database migrations, user interface, release, checks, or production evidence. This change establishes product and technical design contracts only. +ELUNVERA is a newly created public repository. Before this baseline, it contained no branches, commits, runtime, database migrations, user interface, release, checks, or production evidence. This change establishes product and technical design contracts, repository validation, a public documentation source, and an Apache-2.0 grant for ContextualWisdomLab-authored source/documentation only. **Current honest classification:** `design baseline / pre-implementation`. -The repository must not be described as alpha, beta, production-ready, secure, compliant, scalable, accessible, or commercially validated until the corresponding implementation and evidence exist. +The repository must not be described as alpha, beta, production-ready, secure, compliant, scalable, accessible, or commercially validated until the corresponding implementation and evidence exist. The repository source license permits commercial use but is not evidence that a sellable product or a future dependency set is commercially ready. ## 2. Product definition established by this baseline @@ -89,9 +89,9 @@ It deliberately does not own identity, email/calendar/file hosting, generalized ### G-008 Security and supply chain -**Gap:** no CI, SAST, secret scan, dependency review, SBOM, provenance, signatures, or penetration test. -**Risk:** no trustworthy artifact exists. -**Action:** use central `.github` reusable workflows, exact pins, minimal permissions, and signed release pipeline. +**Gap:** no executable-product CI, SAST, secret scan, dependency review, SBOM, provenance, signatures, or penetration test evidence yet. +**Risk:** no trustworthy runtime artifact exists. +**Action:** use central `.github` reusable workflows, exact pins, minimal permissions, and a signed release pipeline as executable code is introduced. **Exit evidence:** current-head checks and signed release candidate. ### G-009 Operability @@ -110,10 +110,12 @@ It deliberately does not own identity, email/calendar/file hosting, generalized ### G-011 Commercial and legal readiness -**Gap:** no software license, trademark registration, terms, DPA, support policy, pricing, entitlement, or billing integration. -**Risk:** a public design repository is not a sellable product. -**Action:** decide license, complete trademark/legal review, define deployment/support and Billing Control Plane integration after core product evidence. -**Exit evidence:** approved legal/commercial package. +**Resolved slice:** ContextualWisdomLab-authored ELUNVERA source and documentation now have an explicit Apache License 2.0 repository grant under accepted ADR-0013. The license permits commercial use and distribution and keeps trademark and third-party rights separate. + +**Remaining gap:** no trademark registration evidence, terms, DPA, support policy, pricing, entitlement, billing integration, or dependency/asset license inventory for a future executable distribution. +**Risk:** a licensed public design repository is still not a sellable or legally complete product, and future imported components may carry independent obligations. +**Action:** complete trademark/legal review, product terms/DPA/support model, dependency and asset provenance inventory, deployment/support offer, and Billing Control Plane integration after core product evidence exists. +**Exit evidence:** reviewed commercial/legal package plus exact distributable dependency/SBOM/license/attribution evidence. ### G-012 Product validation @@ -139,4 +141,4 @@ repository governance ## 6. Release truth -The documentation baseline closes the absence of a coherent product definition and implementation contract. It closes none of the runtime, security, privacy, accessibility, model-validity, scalability, operational, legal, or market-validation gaps listed above. +The documentation baseline closes the absence of a coherent product definition, implementation contract, public repository source-license decision, and source-documentation navigation. It closes none of the runtime, security, privacy, accessibility, model-validity, scalability, operational, broader legal/commercial, or market-validation gaps listed above. No release exists until an exact protected executable source and its required artifact, dependency, SBOM, provenance, review, and operational evidence are independently established. From 1523282e8f84fd68bea6e61112f80a90fddecfce Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 14:30:31 +0900 Subject: [PATCH 53/87] docs: make public landing license-aware --- docs/index.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 1bfce12..84ed273 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,7 +6,7 @@ ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence pl ## Start here -- [Repository README](../README.md) — product promise, bounded responsibility, development status, and documentation map. +- [Repository README](https://github.com/ContextualWisdomLab/ELUNVERA/blob/develop/README.md) — product promise, bounded responsibility, development status, and documentation map. - [Product requirements](PRD.md) — users, jobs, requirements, scope, and release criteria. - [Technical requirements](TRD.md) — platform constraints and implementation contracts. - [Architecture](ARCHITECTURE.md) — bounded contexts, components, trust zones, and deployment model. @@ -20,6 +20,7 @@ ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence pl - [Architecture decisions](adr/README.md) — accepted and proposed product/technical decisions. - [Product/technical gap baseline](product-technical-gap-baseline.md) — current evidence, missing capabilities, and next actions. - [Research and standards references](doctoring/REFERENCES.md) — APA-style source register. +- [Apache License 2.0](https://github.com/ContextualWisdomLab/ELUNVERA/blob/develop/LICENSE) — repository grant for ContextualWisdomLab-authored source and documentation. ## Product boundary @@ -35,6 +36,10 @@ The current reviewed source is a documentation and machine-readable contract bas Begin with the PRD, TRD, architecture, data model, and API contract before implementing a product slice. The repository's permanent document/contract workflow and current protected-branch checks remain the integration authority. Any implementation must preserve the documented bitemporal/evidence model, normalized PostgreSQL system-of-record boundary, explicit service contracts, accessibility target, and security/privacy constraints. +## License and rights boundary + +ContextualWisdomLab-authored ELUNVERA source and documentation are licensed under Apache License 2.0. That grant does not assert trademark registration and does not relicense standards, dependencies, generated assets, datasets, models, provider services, or future imported material. Those components remain subject to independent provenance, commercial-license compatibility, and attribution review. + ## Releases and deeper exploration - [GitHub Releases](https://github.com/ContextualWisdomLab/ELUNVERA/releases) From 9fc86f5e8915b5be67373b03ca47f6ea23ce8258 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:27:04 +0900 Subject: [PATCH 54/87] ci: validate docs on canonical main PRs --- .github/workflows/document-contracts.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/document-contracts.yml b/.github/workflows/document-contracts.yml index a7d580b..984ffb8 100644 --- a/.github/workflows/document-contracts.yml +++ b/.github/workflows/document-contracts.yml @@ -3,10 +3,11 @@ name: document-contracts on: pull_request: branches: + - main - develop push: branches: - - develop + - main workflow_dispatch: permissions: From b9101a76153cf2a66d3ef014854f412383d2634b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:31:51 +0900 Subject: [PATCH 55/87] ci: review canonical main pull requests --- .coderabbit.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.coderabbit.yaml b/.coderabbit.yaml index d82aee4..6e244fc 100644 --- a/.coderabbit.yaml +++ b/.coderabbit.yaml @@ -2,5 +2,6 @@ reviews: auto_review: enabled: true base_branches: + - main - develop review_status: true From 40c694a596551810bc48eac3183fe6e8f713bff5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:33:01 +0900 Subject: [PATCH 56/87] docs: align integration branch with protected main --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e9506bf..43b5f14 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ This repository currently contains a **documentation and contract baseline only* ## Working conventions -- Primary integration branch: `develop` +- Primary integration branch: `main` - Review flow: feature branch → current-head checks → independent review → squash merge - Database object names: two or more words in `snake_case` - Production arithmetic and model computation: Rust From 6b1c71c24782a26735afc7d6b9b300ee437dacdc Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:33:31 +0900 Subject: [PATCH 57/87] docs: point public navigation at canonical main --- docs/index.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/index.md b/docs/index.md index 84ed273..ba86621 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,7 +6,7 @@ ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence pl ## Start here -- [Repository README](https://github.com/ContextualWisdomLab/ELUNVERA/blob/develop/README.md) — product promise, bounded responsibility, development status, and documentation map. +- [Repository README](https://github.com/ContextualWisdomLab/ELUNVERA/blob/main/README.md) — product promise, bounded responsibility, development status, and documentation map. - [Product requirements](PRD.md) — users, jobs, requirements, scope, and release criteria. - [Technical requirements](TRD.md) — platform constraints and implementation contracts. - [Architecture](ARCHITECTURE.md) — bounded contexts, components, trust zones, and deployment model. @@ -20,7 +20,7 @@ ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence pl - [Architecture decisions](adr/README.md) — accepted and proposed product/technical decisions. - [Product/technical gap baseline](product-technical-gap-baseline.md) — current evidence, missing capabilities, and next actions. - [Research and standards references](doctoring/REFERENCES.md) — APA-style source register. -- [Apache License 2.0](https://github.com/ContextualWisdomLab/ELUNVERA/blob/develop/LICENSE) — repository grant for ContextualWisdomLab-authored source and documentation. +- [Apache License 2.0](https://github.com/ContextualWisdomLab/ELUNVERA/blob/main/LICENSE) — repository grant for ContextualWisdomLab-authored source and documentation. ## Product boundary From 8703232569284a08b22d7fb44ecc2d9f06b23f06 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:40:43 +0900 Subject: [PATCH 58/87] docs: keep license ADR Proposed until integration --- docs/adr/0013-brand-and-license.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/adr/0013-brand-and-license.md b/docs/adr/0013-brand-and-license.md index 79fe925..8b465c3 100644 --- a/docs/adr/0013-brand-and-license.md +++ b/docs/adr/0013-brand-and-license.md @@ -1,6 +1,6 @@ # ADR-0013: Preserve ELUNVERA brand and license original source under Apache-2.0 -- **Status:** Accepted +- **Status:** Proposed - **Date:** 2026-09-02 - **Decision owners:** ELUNVERA maintainers @@ -18,9 +18,11 @@ License ContextualWisdomLab-authored ELUNVERA source and documentation under the The repository grant does not relicense standards, dependencies, generated assets, datasets, models, provider services, trademarks, or future imported material. Every such component requires independent provenance, commercial-license compatibility, and attribution/NOTICE review before incorporation or distribution. +This decision remains Proposed while the foundation PR is unmerged. It may become Accepted only after ordinary protected-branch integration has preserved this license boundary and current validation/review evidence supports the integrated revision. + ## Consequences -- ELUNVERA-authored repository source and documentation have an explicit commercial-use-compatible grant. +- ELUNVERA-authored repository source and documentation have an explicit commercial-use-compatible grant on this branch. - Brand and trademark rights remain separate from source licensing; no trademark registration or broader brand permission is claimed. - Future package/dependency/source/asset additions must be checked independently and cannot rely on Apache-2.0 to override their original terms. - A future incompatible inbound obligation requires replacement/removal or a superseding, evidence-backed repository decision rather than a silent exception. From ba50300240794d21d47daaae7c59db7772435f8a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:41:04 +0900 Subject: [PATCH 59/87] docs: align ADR index with Draft foundation status --- docs/adr/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/adr/README.md b/docs/adr/README.md index 149e937..bbbdbe8 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -16,7 +16,7 @@ Status values: `Proposed`, `Accepted`, `Superseded`, `Rejected`. | [0010](./0010-rust-compute-boundary.md) | Use Rust for production computation and prohibit heuristic scores | Proposed | | [0011](./0011-contract-versioning.md) | Version HTTP and events independently | Proposed | | [0012](./0012-quality-release-gates.md) | Require evidence-based release gates | Proposed | -| [0013](./0013-brand-and-license.md) | Preserve brand boundaries; license original source under Apache-2.0 | Accepted | +| [0013](./0013-brand-and-license.md) | Preserve brand boundaries; license original source under Apache-2.0 | Proposed | | [0014](./0014-ux-design-system.md) | Use a three-band account UX and shared design system | Proposed | | [0015](./0015-retention-disposition.md) | Make retention, legal hold, and disposition explicit workflows | Proposed | | [0016](./0016-cwl-ecosystem-boundaries.md) | Integrate CWL products without direct SQL or code copying | Proposed | From 82e64880983cf8eab42d61475451e1f62331753f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:41:43 +0900 Subject: [PATCH 60/87] docs: reconcile governance and Draft decision evidence --- docs/product-technical-gap-baseline.md | 33 +++++++++++++++----------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index c731663..a375b01 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,18 +1,18 @@ # ELUNVERA Product–Technical Gap Baseline -- **Baseline version:** 0.2 +- **Baseline version:** 0.3 - **Observed date:** 2026-09-02 - **Repository:** `ContextualWisdomLab/ELUNVERA` -- **Target integration branch:** `develop` -- **Evidence scope:** repository metadata plus this documentation and source-license change +- **Target integration branch:** `main` +- **Evidence scope:** live repository metadata plus this documentation and source-license change ## 1. Executive status -ELUNVERA is a newly created public repository. Before this baseline, it contained no branches, commits, runtime, database migrations, user interface, release, checks, or production evidence. This change establishes product and technical design contracts, repository validation, a public documentation source, and an Apache-2.0 grant for ContextualWisdomLab-authored source/documentation only. +ELUNVERA is a newly created public, non-fork repository whose protected `main` branch remains at the bootstrap revision while this Draft foundation is reviewed. The foundation branch establishes product and technical design contracts, repository validation, a public documentation source, and a proposed Apache-2.0 grant for ContextualWisdomLab-authored source/documentation only. It still contains no production runtime, database migration, customer deployment, benchmark, or immutable release. **Current honest classification:** `design baseline / pre-implementation`. -The repository must not be described as alpha, beta, production-ready, secure, compliant, scalable, accessible, or commercially validated until the corresponding implementation and evidence exist. The repository source license permits commercial use but is not evidence that a sellable product or a future dependency set is commercially ready. +The repository must not be described as alpha, beta, production-ready, secure, compliant, scalable, accessible, or commercially validated until the corresponding implementation and evidence exist. The proposed repository source license permits commercial use if integrated as written, but is not evidence that a sellable product or a future dependency set is commercially ready. ## 2. Product definition established by this baseline @@ -40,10 +40,15 @@ It deliberately does not own identity, email/calendar/file hosting, generalized ### G-001 Repository governance -**Gap:** no committed `develop` branch, ruleset, CODEOWNERS, required checks, labels, or release policy. -**Risk:** changes can bypass current-head review and the requested PR flow. -**Action:** establish bootstrap commit, `develop`, branch ruleset, independent approval, unresolved-thread protection, required checks, update-branch, squash merge, and branch deletion policy. -**Exit evidence:** ruleset API snapshot and tested PR. +**Current evidence:** `main` and `develop` exist at the same bootstrap revision, but `main` is the canonical protected integration branch. The organization default-branch ruleset applies ordinary review protection, including qualifying approval and unresolved-thread protection. This Draft PR now targets `main`; its permanent document-contract workflow and CodeRabbit configuration were repaired to include `main` after the retarget. + +**Remaining gap:** exact-head required workflow completion, current semantic review, release-policy evidence, and any repository-specific ownership controls not supplied by the organization baseline remain unproven. `develop` is not a release authority. + +**Risk:** stale branch assumptions or predecessor-head evidence can bypass the intended integration contract even when organization protection exists. + +**Action:** keep `main` canonical; require exact-head document/contract and organization checks plus qualifying independent review; preserve the ruleset rather than weakening it; add repository-specific ownership/release controls only when their responsibility is not already centrally supplied. + +**Exit evidence:** live ruleset snapshot plus a successful ordinary protected PR on the unchanged exact head. ### G-002 Executable Rust foundation @@ -110,12 +115,12 @@ It deliberately does not own identity, email/calendar/file hosting, generalized ### G-011 Commercial and legal readiness -**Resolved slice:** ContextualWisdomLab-authored ELUNVERA source and documentation now have an explicit Apache License 2.0 repository grant under accepted ADR-0013. The license permits commercial use and distribution and keeps trademark and third-party rights separate. +**Proposed slice on this Draft branch:** ContextualWisdomLab-authored ELUNVERA source and documentation are proposed for an explicit Apache License 2.0 repository grant under ADR-0013. The root `LICENSE` and documentation express that boundary, but ADR-0013 remains `Proposed` until ordinary protected-branch integration preserves the decision and its validation evidence. The grant does not imply trademark registration and does not relicense third-party material. **Remaining gap:** no trademark registration evidence, terms, DPA, support policy, pricing, entitlement, billing integration, or dependency/asset license inventory for a future executable distribution. **Risk:** a licensed public design repository is still not a sellable or legally complete product, and future imported components may carry independent obligations. -**Action:** complete trademark/legal review, product terms/DPA/support model, dependency and asset provenance inventory, deployment/support offer, and Billing Control Plane integration after core product evidence exists. -**Exit evidence:** reviewed commercial/legal package plus exact distributable dependency/SBOM/license/attribution evidence. +**Action:** after foundation integration, complete trademark/legal review, product terms/DPA/support model, dependency and asset provenance inventory, deployment/support offer, and Billing Control Plane integration after core product evidence exists. +**Exit evidence:** protected-main license/ADR integration plus reviewed commercial/legal package and exact distributable dependency/SBOM/license/attribution evidence. ### G-012 Product validation @@ -127,7 +132,7 @@ It deliberately does not own identity, email/calendar/file hosting, generalized ## 5. Highest-leverage implementation order ```text -repository governance +canonical-main governance and foundation integration → identity and tenant boundary → PostgreSQL account/party/relationship kernel → audit, outbox, idempotency, temporal APIs @@ -141,4 +146,4 @@ repository governance ## 6. Release truth -The documentation baseline closes the absence of a coherent product definition, implementation contract, public repository source-license decision, and source-documentation navigation. It closes none of the runtime, security, privacy, accessibility, model-validity, scalability, operational, broader legal/commercial, or market-validation gaps listed above. No release exists until an exact protected executable source and its required artifact, dependency, SBOM, provenance, review, and operational evidence are independently established. +This Draft documentation baseline addresses the absence of a coherent product definition, implementation contract, proposed public repository source-license decision, and source-documentation navigation. It closes none of the runtime, security, privacy, accessibility, model-validity, scalability, operational, broader legal/commercial, or market-validation gaps listed above, and it does not mark a decision Accepted merely because it exists on an unmerged branch. No release exists until an exact protected executable source and its required artifact, dependency, SBOM, provenance, review, and operational evidence are independently established. From 9fcb3c27377811005d9dde2bec20744da2904419 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:43:17 +0900 Subject: [PATCH 61/87] docs: record canonical-main governance repairs --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b03365..660359e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ The format follows Keep a Changelog principles, and versioning will begin when t - Corrected AsyncAPI operations to publish ELUNVERA domain events and required classification/schema metadata. - Added explicit `recorded_at` payload fields so outbox publication delay cannot corrupt bitemporal reconstruction. - Removed one-shot reconciliation/review-repair workflows and script from the publishable candidate before final manifest sealing. +- Retargeted the Draft foundation to canonical protected `main`, aligned document-contract and review automation with that base, and corrected stale `develop` navigation/governance claims. +- Returned ADR-0013 to `Proposed` while the foundation remains unmerged; protected integration is required before the decision may be marked `Accepted`. ### Security From c1bddee033fe3ccc9590d10412875b8b5faafd4b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:48:00 +0900 Subject: [PATCH 62/87] chore: reseal exact foundation manifest --- manifest.json | 62 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/manifest.json b/manifest.json index 97c7637..ce152fa 100644 --- a/manifest.json +++ b/manifest.json @@ -1,11 +1,17 @@ { "schema_version": "1.0", "product": "ELUNVERA", - "generated_at": "2026-08-29T12:50:00Z", + "generated_at": "2026-09-02T09:46:50Z", "algorithm": "SHA-256", "self_excluded": true, - "file_count": 55, + "file_count": 58, "files": [ + { + "path": ".coderabbit.yaml", + "sha256": "efe46b993fae145eeaa2b2fb2cf0c302000c6373e5246c8e54bf330d636f4e2b", + "size_bytes": 112, + "line_count": 7 + }, { "path": ".cwl/data-management.yaml", "sha256": "28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671", @@ -20,9 +26,9 @@ }, { "path": ".github/workflows/document-contracts.yml", - "sha256": "4753940663837d4326b3954a300545738ec5a16ef72bd9e6cfcadc6ab2ea00f1", - "size_bytes": 7127, - "line_count": 160 + "sha256": "276d5f02fa4f0f2d93098dd4f421cb91f0aee0925808c6f6925840ef07bee2c5", + "size_bytes": 7137, + "line_count": 161 }, { "path": "AGENTS.md", @@ -32,9 +38,9 @@ }, { "path": "CHANGELOG.md", - "sha256": "e156a07dcc8e31ab59c8145a192eb1c2edaca9d2f2ffd672f6e9c339b704e893", - "size_bytes": 1583, - "line_count": 31 + "sha256": "3f23ce77e9e61a330e53d1a8045a1b9828e142f886cc49dbf465f030dd189f53", + "size_bytes": 2273, + "line_count": 36 }, { "path": "CLAUDE.md", @@ -48,11 +54,17 @@ "size_bytes": 1566, "line_count": 43 }, + { + "path": "LICENSE", + "sha256": "b7fa79459ac09645fd5bed5363852ba8759fa6deeb972d02f09fb0dc50fef586", + "size_bytes": 11290, + "line_count": 192 + }, { "path": "README.md", - "sha256": "9d355be62b9bf5b8e90a6bfa204db40abbf5fd2d9307733501172983c465546c", - "size_bytes": 4974, - "line_count": 81 + "sha256": "3c65f74b492dfe6ae8e06eedd23a5ffde397d06b751d10a29f464c0621b77b04", + "size_bytes": 5471, + "line_count": 84 }, { "path": "SECURITY.md", @@ -164,9 +176,9 @@ }, { "path": "docs/VALIDATION_REPORT.md", - "sha256": "c5a40ac8c25e8beea60a665f943f15ae4dfe12f60a96258b7a74047731fa2f82", - "size_bytes": 2368, - "line_count": 53 + "sha256": "71b913ecac5bea2f94d10933c959bff0c0ba28110ee3be087a8578db08391ab8", + "size_bytes": 2895, + "line_count": 56 }, { "path": "docs/WIREFRAMES.md", @@ -248,9 +260,9 @@ }, { "path": "docs/adr/0013-brand-and-license.md", - "sha256": "9b54fd5c0fc4de13f647e1c8955c69c6cffd90766c8dd946e1d34322a7adc0de", - "size_bytes": 923, - "line_count": 21 + "sha256": "e27ab7029b52981abab21aacb1ed5fec8e458e1ff40163c4ab504c5426544b86", + "size_bytes": 3160, + "line_count": 32 }, { "path": "docs/adr/0014-ux-design-system.md", @@ -272,8 +284,8 @@ }, { "path": "docs/adr/README.md", - "sha256": "b54b4bc29ff5a2d385c23bd7049bc64e1cf04277147afa70057b20ba8b5f46e1", - "size_bytes": 1806, + "sha256": "ebd75a0c60d4dd3bd13f3135b3c81732013d8ace8ccc263b9ca7703fa406f5aa", + "size_bytes": 1818, "line_count": 22 }, { @@ -294,11 +306,17 @@ "size_bytes": 2560, "line_count": 22 }, + { + "path": "docs/index.md", + "sha256": "d7641f7c026b0bba9c7c8539b68c729517aade17de6af3656c5bf2942fded9a3", + "size_bytes": 4611, + "line_count": 49 + }, { "path": "docs/product-technical-gap-baseline.md", - "sha256": "39e5adf829a46271ce3939cbf2259108b25d0ff39c26128c38229a2f808f8301", - "size_bytes": 8851, - "line_count": 142 + "sha256": "f2a2012b9f73eeaaa5d0052eb1328d56cedd23a937acb19850e76f515fa0dccd", + "size_bytes": 11455, + "line_count": 149 }, { "path": "docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md", From df5bc9f57bd3c755dbf804df82e878f028c7efdc Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:54:39 +0900 Subject: [PATCH 63/87] docs: align agent base with canonical main --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 3b232f1..1ed86c8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -71,7 +71,7 @@ Update `CHANGELOG.md`, `docs/product-technical-gap-baseline.md`, affected ADRs, ## Pull request operation -Use `develop` as the base branch unless an explicitly approved stack requires another feature branch. +Use canonical protected `main` as the ordinary product base. A dependency stack may target its verified prerequisite feature branch while that prerequisite remains open; it must return to `main` once the prerequisite is integrated. Before commit or push: From 6a011d923245aad45f803f99756487ca0d98c5e1 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:54:51 +0900 Subject: [PATCH 64/87] docs: align contribution base with canonical main --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 79fc2d9..1840c84 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ ## Branching -- Base product work on `develop`. +- Base ordinary product work on canonical protected `main`; a stacked PR may target its verified prerequisite feature branch until that prerequisite is integrated. - Use bounded branches such as `docs/product-technical-baseline`, `feat/account-registry`, or `fix/tenant-authorization`. - One pull request should deliver one independently reviewable product or platform slice. From 8f33bb9c25de08f606e7e75d59583a541d25a00e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:55:43 +0900 Subject: [PATCH 65/87] docs: make PRD branch authority canonical --- docs/PRD.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/PRD.md b/docs/PRD.md index ca92434..d8a93ce 100644 --- a/docs/PRD.md +++ b/docs/PRD.md @@ -5,7 +5,7 @@ - **Date:** 2026-08-27 - **Product:** ELUNVERA - **Repository:** `ContextualWisdomLab/ELUNVERA` -- **Primary branch:** `develop` +- **Primary branch:** `main` ## 1. Executive summary From 3f5966e8c39fbb4da702b250cd9f4fd44cc0a21e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:56:03 +0900 Subject: [PATCH 66/87] docs: align roadmap with canonical main --- docs/ROADMAP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ROADMAP.md b/docs/ROADMAP.md index ee42b6b..b38912b 100644 --- a/docs/ROADMAP.md +++ b/docs/ROADMAP.md @@ -7,7 +7,7 @@ - PRD, TRD, architecture, data model, security, privacy, threat model, UX, test, operability, ADR, OpenAPI, AsyncAPI, and schemas reviewed; - product boundary accepted; - no implementation or readiness claim mixed into documentation; -- `develop` integration branch and protected review policy established. +- `main` integration branch and protected review policy established. ## M1 — Identity, tenancy, and canonical CRM kernel From 2723797c9c82ba9da74e36a5c728ae9d7a3457c7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:56:34 +0900 Subject: [PATCH 67/87] docs: align foundation spec with canonical main --- .../2026-08-27-elunvera-product-technical-baseline-design.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md b/docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md index 81db2dd..b97ab2c 100644 --- a/docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md +++ b/docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md @@ -6,7 +6,7 @@ ## 1. Intent -Establish a coherent design baseline for a new evidence-centered B2B CRM that can enter implementation through `develop` without absorbing adjacent CWL products or inventing unvalidated commercial scores. +Establish a coherent design baseline for a new evidence-centered B2B CRM that can enter implementation through canonical protected `main` without absorbing adjacent CWL products or inventing unvalidated commercial scores. ## 2. Considered approaches From 728c4163854e04538d7df55aa033c8d2fdffddd7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 18:57:25 +0900 Subject: [PATCH 68/87] docs: align implementation plan with canonical main --- .../plans/2026-08-27-elunvera-foundation-implementation-plan.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md b/docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md index 3563111..9a38939 100644 --- a/docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md +++ b/docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md @@ -12,7 +12,7 @@ ## Global Constraints -- The integration base is `develop`. +- The ordinary integration base is canonical protected `main`; dependency stacks may temporarily target a verified prerequisite feature branch. - Canonical database objects use at least two-word `snake_case` names. - Production logic and arithmetic are Rust; TypeScript is UI/client only. - PostgreSQL is canonical; search and graph are projections. From cff9c6f9769c2600cafd079fbaf62fbfa1e5fed2 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 19:00:19 +0900 Subject: [PATCH 69/87] docs: record canonical branch authority reconciliation --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 660359e..1cc8416 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ The format follows Keep a Changelog principles, and versioning will begin when t - Removed one-shot reconciliation/review-repair workflows and script from the publishable candidate before final manifest sealing. - Retargeted the Draft foundation to canonical protected `main`, aligned document-contract and review automation with that base, and corrected stale `develop` navigation/governance claims. - Returned ADR-0013 to `Proposed` while the foundation remains unmerged; protected integration is required before the decision may be marked `Accepted`. +- Aligned AGENTS, contributing guidance, PRD, roadmap, and implementation plan/spec branch authority with canonical protected `main`; stacked work may target only its verified prerequisite branch. ### Security From c2a1dd934309d89d58e7cd4efe07fcb9df538e7e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 19:01:52 +0900 Subject: [PATCH 70/87] chore: reseal canonical branch manifest --- manifest.json | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/manifest.json b/manifest.json index ce152fa..91b5494 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "schema_version": "1.0", "product": "ELUNVERA", - "generated_at": "2026-09-02T09:46:50Z", + "generated_at": "2026-09-02T09:59:00Z", "algorithm": "SHA-256", "self_excluded": true, "file_count": 58, @@ -32,15 +32,15 @@ }, { "path": "AGENTS.md", - "sha256": "8d308fc7f687ad53e18aabc95cbb175a48450b8bfe502b29562f0afd9c950d13", - "size_bytes": 4022, + "sha256": "6c97e76c8ec1da4d30b82a1759755bae11018c132ca0fd29d7dfc803b55006a1", + "size_bytes": 4152, "line_count": 84 }, { "path": "CHANGELOG.md", - "sha256": "3f23ce77e9e61a330e53d1a8045a1b9828e142f886cc49dbf465f030dd189f53", - "size_bytes": 2273, - "line_count": 36 + "sha256": "cd6a7037573811b5f9f42515f61e7d7d403b6824dd0f53d7e528079134eaa111", + "size_bytes": 2470, + "line_count": 37 }, { "path": "CLAUDE.md", @@ -50,8 +50,8 @@ }, { "path": "CONTRIBUTING.md", - "sha256": "61698c99617bbdd3fab3150341899c967c647cf5aa5ec9756d9cf6fa99571e60", - "size_bytes": 1566, + "sha256": "5aee2d583ac082626a59cca4a832715ab6c9ef0e406ae48c7976887c71a74127", + "size_bytes": 1696, "line_count": 43 }, { @@ -98,8 +98,8 @@ }, { "path": "docs/PRD.md", - "sha256": "8d074776a4cd2a8465daefb98751cf01ffd7ffcb1a328f8deea6362e728ab860", - "size_bytes": 22102, + "sha256": "95576c4d9b20bbc95ed355e5771f7b429d1346cd721b1224c007db1cabd4ae65", + "size_bytes": 22099, "line_count": 366 }, { @@ -110,8 +110,8 @@ }, { "path": "docs/ROADMAP.md", - "sha256": "1a00a118088f908cce4449a1532f35231f383c7d415fff5136624bf970b926c7", - "size_bytes": 3418, + "sha256": "3e94efa42e1553428dd90c8bd6b298b114a1af8188faa0968f690b6dd4f9a486", + "size_bytes": 3415, "line_count": 84 }, { @@ -320,14 +320,14 @@ }, { "path": "docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md", - "sha256": "ed833198cc2e5f7ebcc9f22b402f25dbdc647ce19657c4759c85299f0c37f0fc", - "size_bytes": 16009, + "sha256": "d453a94d4b5d2650aff49619da9733d057c5df80b241fe6a43ee0d95db99ebed", + "size_bytes": 16116, "line_count": 433 }, { "path": "docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md", - "sha256": "3ea901999f778ebe4aa5118024da82f4b72457814f8a715df7440ce41726cb5d", - "size_bytes": 4492, + "sha256": "45debe0ac12d4648d21c0a8fb53fb9b30b07188a6b8e3ce0c9e4e22ebc34d999", + "size_bytes": 4509, "line_count": 67 }, { From 3cbe9e037636471f1f1a1979352c2e5b7c4f434a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 19:04:41 +0900 Subject: [PATCH 71/87] ci: guard canonical main authority --- .github/workflows/document-contracts.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/document-contracts.yml b/.github/workflows/document-contracts.yml index 984ffb8..ccae7e4 100644 --- a/.github/workflows/document-contracts.yml +++ b/.github/workflows/document-contracts.yml @@ -82,6 +82,10 @@ jobs: provenance = envelope.fetch('properties').fetch('provenanceref') raise 'provenance must be a non-null string' unless provenance['type'] == 'string' raise 'provenance must reject empty values' unless provenance['minLength'].to_i >= 1 + + coderabbit = YAML.safe_load(File.read('.coderabbit.yaml'), aliases: false) + review_bases = coderabbit.fetch('reviews').fetch('auto_review').fetch('base_branches') + raise 'CodeRabbit must review canonical main PRs' unless review_bases.include?('main') RUBY python - <<'PY' @@ -106,6 +110,17 @@ jobs: missing = sorted(str(path) for path in required if not path.is_file()) assert not missing, missing + branch_markers = { + Path('AGENTS.md'): 'Use canonical protected `main` as the ordinary product base.', + Path('CONTRIBUTING.md'): 'Base ordinary product work on canonical protected `main`', + Path('docs/PRD.md'): '- **Primary branch:** `main`', + Path('docs/ROADMAP.md'): '`main` integration branch and protected review policy established.', + Path('docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md'): 'The ordinary integration base is canonical protected `main`', + Path('docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md'): 'through canonical protected `main`', + } + for path, marker in branch_markers.items(): + assert marker in path.read_text(encoding='utf-8'), f'canonical-main authority drift: {path}' + for event_path in ( Path('schemas/events/relationship-changed-v1.schema.json'), Path('schemas/events/opportunity-stage-changed-v1.schema.json'), From 86b87bf54cc75255ea7ba02eef18766a2e44213d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 19:05:08 +0900 Subject: [PATCH 72/87] docs: record branch-authority contract guard --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cc8416..53dbc92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,7 +26,7 @@ The format follows Keep a Changelog principles, and versioning will begin when t - Removed one-shot reconciliation/review-repair workflows and script from the publishable candidate before final manifest sealing. - Retargeted the Draft foundation to canonical protected `main`, aligned document-contract and review automation with that base, and corrected stale `develop` navigation/governance claims. - Returned ADR-0013 to `Proposed` while the foundation remains unmerged; protected integration is required before the decision may be marked `Accepted`. -- Aligned AGENTS, contributing guidance, PRD, roadmap, and implementation plan/spec branch authority with canonical protected `main`; stacked work may target only its verified prerequisite branch. +- Aligned AGENTS, contributing guidance, PRD, roadmap, and implementation plan/spec branch authority with canonical protected `main`; stacked work may target only its verified prerequisite branch, and document-contract CI now guards that authority against drift. ### Security From 862222a29da4113d80549a7fb237a73a338e0b22 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 19:08:27 +0900 Subject: [PATCH 73/87] chore: reseal branch-authority manifest --- manifest.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/manifest.json b/manifest.json index 91b5494..da0dd3c 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "schema_version": "1.0", "product": "ELUNVERA", - "generated_at": "2026-09-02T09:59:00Z", + "generated_at": "2026-09-02T10:06:00Z", "algorithm": "SHA-256", "self_excluded": true, "file_count": 58, @@ -26,9 +26,9 @@ }, { "path": ".github/workflows/document-contracts.yml", - "sha256": "276d5f02fa4f0f2d93098dd4f421cb91f0aee0925808c6f6925840ef07bee2c5", - "size_bytes": 7137, - "line_count": 161 + "sha256": "7ccb26e8cf0c6018a3286b9454a447a6f858b095a0f5a7e89937709eab13618f", + "size_bytes": 8296, + "line_count": 176 }, { "path": "AGENTS.md", @@ -38,8 +38,8 @@ }, { "path": "CHANGELOG.md", - "sha256": "cd6a7037573811b5f9f42515f61e7d7d403b6824dd0f53d7e528079134eaa111", - "size_bytes": 2470, + "sha256": "6a7c7b82208a23ac493edb4df481c95b77fbeef1551856bb39a941f9ea054214", + "size_bytes": 2536, "line_count": 37 }, { From 3dce11863834106794bbbeba1b80cb038112d2bf Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 20:22:17 +0900 Subject: [PATCH 74/87] test(docs): fail closed on performance and locale contract drift --- .github/workflows/document-contracts.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/document-contracts.yml b/.github/workflows/document-contracts.yml index ccae7e4..3d13ca5 100644 --- a/.github/workflows/document-contracts.yml +++ b/.github/workflows/document-contracts.yml @@ -121,6 +121,30 @@ jobs: for path, marker in branch_markers.items(): assert marker in path.read_text(encoding='utf-8'), f'canonical-main authority drift: {path}' + product_contract_markers = { + Path('docs/PRD.md'): ( + 'p95 ≤ 20 ms', + 'Korean, English, Japanese, Chinese, Vietnamese, Spanish, German, and French', + 'DB-backed, versioned translation resources', + ), + Path('docs/TRD.md'): ( + 'server/native clients fetch and cache only the screen keys they need', + 'p95 ≤ 20 ms', + ), + Path('docs/UX_SPEC.md'): ( + 'Korean, English, Japanese, Chinese, Vietnamese, Spanish, German, and French', + 'DB-backed, versioned translation resources', + ), + Path('docs/TEST_STRATEGY.md'): ( + 'p95 ≤ 20 ms', + 'ko/en/ja/zh/vi/es/de/fr', + ), + } + for path, markers in product_contract_markers.items(): + text = path.read_text(encoding='utf-8') + for marker in markers: + assert marker in text, f'commercialization contract drift: {path}: {marker}' + for event_path in ( Path('schemas/events/relationship-changed-v1.schema.json'), Path('schemas/events/opportunity-stage-changed-v1.schema.json'), From 589c572c7e7160fe12aa5770ece0be5ffaaf3a90 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 20:24:33 +0900 Subject: [PATCH 75/87] docs(prd): adopt eight-locale and 20ms buyer contracts --- docs/PRD.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/docs/PRD.md b/docs/PRD.md index d8a93ce..e92985c 100644 --- a/docs/PRD.md +++ b/docs/PRD.md @@ -1,8 +1,8 @@ # ELUNVERA Product Requirements Document -- **Document version:** 0.1 +- **Document version:** 0.2 - **Status:** Proposed product baseline -- **Date:** 2026-08-27 +- **Date:** 2026-09-02 - **Product:** ELUNVERA - **Repository:** `ContextualWisdomLab/ELUNVERA` - **Primary branch:** `main` @@ -83,7 +83,7 @@ Every alert, empty state, error, and AI response explains what happened, why it ### Initial deployment profile -The first commercial profile is a multi-tenant or customer-isolated enterprise SaaS deployment for Korean and international B2B account teams, with Korean and English user experiences and optional customer-controlled connectors. +The first commercial profile is a multi-tenant or customer-isolated enterprise SaaS deployment for Korean and international B2B account teams. Korean, English, Japanese, Chinese, Vietnamese, Spanish, German, and French ship as first-release interface locales, with optional customer-controlled connectors. ## 6. Personas @@ -146,7 +146,8 @@ When a person requests access, export, correction, restriction, or deletion, ide - immutable audit and transactional outbox; - deterministic CSV/JSON import and export; - account search and duplicate-candidate workflow; -- Korean and English interface baseline; +- Korean, English, Japanese, Chinese, Vietnamese, Spanish, German, and French interface baseline; +- DB-backed, versioned translation resources with review, approval, deployment, rollback, and screen-key-scoped delivery; - account overview, relationship map, timeline, opportunity workspace, and action queue. ### 8.2 P1 — Integrated context @@ -262,8 +263,8 @@ ELUNVERA will not initially: ### Performance -- **NFR-010:** Core account overview p95 server response time shall be under 500 ms for the release benchmark profile, excluding downstream AI calls. -- **NFR-011:** Search p95 shall be under 1.5 seconds for the release benchmark profile. +- **NFR-010:** Every buyer-facing page shall achieve realistic end-to-end p95 ≤ 20 ms under the declared release benchmark profile. The measurement must include the page request, product-owned data access, rendering, and ready-to-interact boundary; it may not be met by shrinking datasets, excluding slow samples, or using an unrealistic warmup. Long-running AI or connector work remains an explicit asynchronous job and may not block page readiness. +- **NFR-011:** Search-backed pages are subject to the same p95 ≤ 20 ms page target. Deep or unbounded exploration that cannot satisfy the interactive budget shall be paginated or moved to an explicit asynchronous workflow rather than weakening the page SLO. - **NFR-012:** Long-running exports, imports, model runs, and connector synchronizations shall use durable asynchronous jobs with status and cancellation. - **NFR-013:** Product UI shall never wait synchronously for an LLM workflow to complete. @@ -293,7 +294,7 @@ These are acceptance targets, not current performance claims. - **NFR-030:** Web experiences shall conform to WCAG 2.2 AA. - **NFR-031:** Every graph, chart, and timeline shall have an exact-value table and export representation. -- **NFR-032:** Korean and English shall ship together, with locale-safe dates, names, addresses, number formats, and sorting. +- **NFR-032:** Korean, English, Japanese, Chinese, Vietnamese, Spanish, German, and French shall ship together, with locale-safe dates, names, addresses, number formats, sorting, font fallback, CJK behavior, and expansion-safe layouts. Translation authority shall use DB-backed, versioned translation resources with review, approval, deployment, and rollback; server/native clients fetch and cache only screen-scoped keys rather than downloading a full browser catalog. - **NFR-033:** Customer-facing copy shall describe the user’s next action rather than internal implementation boundaries. ### Quality @@ -354,7 +355,9 @@ A first production release may be proposed only when: - current-head tests and security checks pass; - tenant isolation is proven at API and database layers; - migrations, rollback, backup, and restore are rehearsed; -- exact user journeys pass in Korean and English; +- exact user journeys pass in Korean, English, Japanese, Chinese, Vietnamese, Spanish, German, and French; +- every buyer-facing page meets the declared realistic k6 p95 ≤ 20 ms release profile without excluded slow samples or synthetic production traffic; +- translation-resource review, approval, cache invalidation, deployment, and rollback are exercised against DB-backed versioned resources; - accessibility journeys pass with keyboard and screen-reader evidence; - no critical or high unaccepted security finding remains; - every numerical model in the release has documented validation and uncertainty; From d9917c61c0c6530bbde7a296e57790bd5bc76825 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 20:25:29 +0900 Subject: [PATCH 76/87] docs(trd): bind runtime, locale and translation contracts --- docs/TRD.md | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/docs/TRD.md b/docs/TRD.md index 23ebf4a..4b93f12 100644 --- a/docs/TRD.md +++ b/docs/TRD.md @@ -1,8 +1,8 @@ # ELUNVERA Technical Requirements Document -- **Document version:** 0.1 +- **Document version:** 0.2 - **Status:** Proposed technical baseline -- **Date:** 2026-08-27 +- **Date:** 2026-09-02 ## 1. Technical objective @@ -52,6 +52,7 @@ ELUNVERA/ │ ├── customer_outcomes/ │ ├── complaint_management/ │ ├── privacy_rights/ +│ ├── translation_resources/ │ ├── audit_provenance/ │ ├── integration_outbox/ │ ├── search_projection/ @@ -138,7 +139,13 @@ Owns desired outcomes, observations, complaint lifecycle, remedies, satisfaction Owns purpose registry, communication preferences, consent or other processing-basis references, data-rights cases, retention decisions, legal hold, disposition receipts, and export manifests. -### 5.10 Audit and provenance +### 5.10 Translation resources + +ELUNVERA owns its product UI translation authority until a separately released CWL translation product proves a reusable contract. The bounded context owns review, approval, deployment, rollback, and immutable revision history for screen-key resources in `ko`, `en`, `ja`, `zh`, `vi`, `es`, `de`, and `fr`. UI translation resources remain distinct from ontology labels and product-domain ubiquitous language. + +The relational model uses multi-word 3NF objects such as `translation_resource`, `translation_revision`, and `translation_text`. Runtime server/native clients fetch and cache only the screen keys they need, with revision-aware invalidation; the browser must not download a full translation catalog or require a heavyweight client i18n runtime. + +### 5.11 Audit and provenance Owns immutable audit events, source receipts, model claims, evidence links, event publication receipts, and data-transformation lineage. @@ -148,7 +155,7 @@ Owns immutable audit events, source receipts, model claims, evidence links, even - PostgreSQL is the authoritative store. - Canonical domain data is normalized to 3NF. -- JSONB is restricted to immutable provider payload metadata, schema-versioned extension values, or diagnostic context that does not determine money, authorization, tenancy, stage, relationship truth, or model score. +- JSONB is restricted to immutable provider payload metadata, schema-versioned extension values, or diagnostic context that does not determine money, authorization, tenancy, stage, relationship truth, model score, or translation publication state. - Graph, search, vector, analytics, and dashboard stores are rebuildable projections. - External system identifiers are isolated in mapping tables. @@ -201,6 +208,7 @@ A tenant ID alone must not create a single unbounded hot partition. - Retries with the same key and payload return the same result. - Reuse of a key with a different payload fails closed. - Every ingestion batch has item-level results; one malformed item does not silently discard neighboring items. +- Translation publication is revision-addressed; item-level UPSERT is explicit for draft resource editing, while approved/released revisions remain immutable and rollback selects a prior immutable revision rather than mutating history. ## 8. HTTP requirements @@ -259,12 +267,14 @@ The normalized relationship store is authoritative. A graph projection may be re - Core CRUD, search filters, authorization, exports, and workflow state do not require an LLM. - All LLM requests go through `contextual-orchestrator`. -- Prompt, provider, model, reasoning level, tool access, source references, result schema, and verification status are recorded. +- GitHub Actions model-backed workflows use only the released contextual-orchestrator gateway with `orchestrator/free`; workflow code does not select a provider, model, group, or paid fallback. +- Prompt, provider, model, reasoning level, tool access, source references, result schema, and verification status are recorded where the released contextual-orchestrator contract exposes them. - Source documents are untrusted content and cannot alter system policy or tool permissions. - Outputs use strict JSON Schema. - Unsupported claims are removed or marked unsupported. - An assistant action is separated into proposal, authorization, execution, observation, and verification. - Model fallback must preserve operation capability; chat, embeddings, image, audio, and structured outputs are not interchangeable. +- Default model timeout is unset unless an administrator explicitly configures one; user cancellation, provider completion, and administrative timeout are distinct terminal causes. ## 12. Numerical model requirements @@ -310,15 +320,18 @@ A connector capability manifest declares read, propose, write, delete, export, w - Exports require purpose, field policy, bounded scope, and a signed receipt. - Model and connector content is untrusted. -## 15. Frontend requirements +## 15. Frontend and page-performance requirements - Design tokens are the only source for repeated spacing, typography, color, elevation, and motion. -- Shared components are documented in Storybook with loading, empty, error, access-denied, stale, conflict, partial-data, and offline states. +- Shared components are documented in Storybook with normal, loading, empty, error, access-denied, stale, conflict, partial-data, offline, permission, responsive, and interaction states. - Figma file ID and component mapping are recorded before production UI acceptance. - Account overview uses three horizontal bands: context, relationships, and action. - A generic floating chat box is not the primary interface; evidence-grounded assistance is embedded in the active account or workflow context. - Every write action has pending, success, retryable failure, and conflict states. - No internal repository or service name appears in customer-facing copy. +- Every buyer-facing page is exercised with realistic k6 end-to-end load and must reach p95 ≤ 20 ms at the ready-to-interact boundary for the declared release profile. Slow samples, realistic dataset volume, database/query/render time, browser bundle/heap/DOM/hydration/main-thread/GC cost, and cold-path effects may not be hidden to satisfy the SLO. +- When the target is missed, profile and repair the causal algorithm, query, I/O, rendering, runtime, or Rust hot path rather than shrinking the sample or weakening the target. +- Product-owned forms and pages support `ko`, `en`, `ja`, `zh`, `vi`, `es`, `de`, and `fr`, including CJK, expansion, font-fallback, wrapping, keyboard, touch, and responsive evidence. ## 16. Operations requirements @@ -329,6 +342,7 @@ A connector capability manifest declares read, propose, write, delete, export, w - SLOs cover interactive API, background jobs, event projection, connectors, and data-rights workflows. - Backup, restore, key availability, and projection rebuild are rehearsed. - Release and rollback are versioned and observable. +- Compose deployment remains compatible with Docker, Podman, and Colima and is structured for later Kubernetes migration; PostgreSQL/application/shm settings are hardware-tuned only from measured container limits. ## 17. Build and supply-chain requirements From 867505145aee4f774d5468a5785ec7c4c83da854 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 20:25:58 +0900 Subject: [PATCH 77/87] docs(ux): define eight-locale versioned translation UX --- docs/UX_SPEC.md | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/UX_SPEC.md b/docs/UX_SPEC.md index e4da194..3c42ee6 100644 --- a/docs/UX_SPEC.md +++ b/docs/UX_SPEC.md @@ -1,8 +1,8 @@ # ELUNVERA UX Specification -- **Document version:** 0.1 +- **Document version:** 0.2 - **Status:** Proposed interaction baseline -- **Date:** 2026-08-27 +- **Date:** 2026-09-02 ## 1. Experience objective @@ -103,7 +103,7 @@ DataRightsCasePanel OperationReceipt ``` -Each component has loading, empty, partial, stale, access-denied, conflict, offline, error, and completed states. +Each component has normal, loading, empty, partial, stale, access-denied, permission, conflict, offline, error, responsive, interaction, and completed states in Storybook before production acceptance. ## 6. Interaction rules @@ -146,9 +146,13 @@ Target: WCAG 2.2 AA. - drag-and-drop has button and keyboard alternatives; - errors identify the field, cause, and recovery action. -## 9. Internationalization +## 9. Internationalization and translation authority -Korean and English are first-release interface languages. Copy is not concatenated from fragments. Dates, names, addresses, currencies, time zones, honorifics, and organization order are locale-aware. The canonical data model does not assume Western given-name or organization formats. +Korean, English, Japanese, Chinese, Vietnamese, Spanish, German, and French are first-release interface languages. Copy is not concatenated from fragments. Dates, names, addresses, currencies, time zones, honorifics, organization order, font fallback, CJK behavior, and text expansion are locale-aware. The canonical data model does not assume Western given-name or organization formats. + +Translation authority uses DB-backed, versioned translation resources with explicit draft, review, approval, deployment, rollback, and immutable revision history. Server/native delivery fetches and caches only screen-scoped keys and revisions. The browser does not receive the full translation catalog and does not require a heavyweight i18n runtime. Product UI copy and ontology labels are separate responsibilities. + +Figma and Storybook must exercise every supported locale at expansion-prone and CJK-sensitive sizes, including navigation, forms, validation, empty/error/permission states, charts/tables, modals, destructive confirmation, and mobile action edges. ## 10. Responsive behavior @@ -159,13 +163,16 @@ Korean and English are first-release interface languages. Copy is not concatenat ## 11. Design system and Figma -A Figma file is required before implementation of the production interface. Its file ID is recorded in an ADR once created. Design tokens are source-controlled and shared with Storybook. The Figma library must cover account overview, relationship exploration, opportunity review, complaint recovery, exports, all edge states, Korean/English copy, keyboard focus, and print. +A Figma file is required before implementation of the production interface. Its file ID is recorded in an ADR once created. Design tokens are source-controlled and shared with Storybook. The Figma library must cover account overview, relationship exploration, opportunity review, complaint recovery, exports, all edge states, all eight release locales, keyboard focus, touch interactions, responsive layouts, and print. + +shadcn/ui, when selected, is imported as product-owned component source rather than treated as an external runtime design authority. Reusable components are validated in Storybook before page composition. ## 12. UX validation - task-based usability testing with account executives, account managers, customer-success users, operations administrators, and privacy/security reviewers; - accessibility audit with automated and assistive-technology testing; -- screenshot review at desktop, tablet, and mobile breakpoints; -- performance checks for timeline and relationship visualization; +- screenshot review at desktop, tablet, and mobile breakpoints across all eight release locales; +- keyboard, touch, focus-not-obscured, responsive, typography/color, reduced-motion, forms/feedback, navigation, charts/data, and action-edge audits; +- realistic k6 page journeys with p95 ≤ 20 ms at the ready-to-interact boundary; slow samples and rendering/main-thread costs are retained in the denominator; - copy review ensuring customer action language and absence of internal implementation boundaries; - event instrumentation reviewed for privacy and semantic consistency. From 2dea0a4bf0ddd18a465a8fa1ee08c425ea6e4152 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 20:26:34 +0900 Subject: [PATCH 78/87] docs(test): enforce realistic 20ms and eight-locale evidence --- docs/TEST_STRATEGY.md | 60 ++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/docs/TEST_STRATEGY.md b/docs/TEST_STRATEGY.md index 8a563cb..095b46b 100644 --- a/docs/TEST_STRATEGY.md +++ b/docs/TEST_STRATEGY.md @@ -1,12 +1,12 @@ # ELUNVERA Test Strategy -- **Document version:** 0.1 +- **Document version:** 0.2 - **Status:** Proposed quality baseline -- **Date:** 2026-08-27 +- **Date:** 2026-09-02 ## 1. Objective -Testing must demonstrate product behavior, tenant and privacy boundaries, temporal correctness, scientific validity, accessibility, performance, recovery, and release reproducibility. Test counts or green status without realistic assertions are not sufficient evidence. +Testing must demonstrate product behavior, tenant and privacy boundaries, temporal correctness, scientific validity, accessibility, internationalization, performance, recovery, and release reproducibility. Test counts or green status without realistic assertions are not sufficient evidence. ## 2. Quality gates @@ -26,7 +26,7 @@ Generated clients and third-party code are measured separately and may not dilut ### Unit tests -Validate domain state transitions, temporal interval operations, identifier handling, currency arithmetic, policy decisions, schema transformations, and error paths. +Validate domain state transitions, temporal interval operations, identifier handling, currency arithmetic, policy decisions, translation-resource revision transitions, schema transformations, and error paths. ### Property tests @@ -38,19 +38,21 @@ Generate sequences of commands and prove invariants including: - idempotent command replay produces one event and one aggregate version; - stage history never disappears after correction; - disclosure decisions are monotonic with stricter policy; -- relationship participants remain tenant-consistent. +- relationship participants remain tenant-consistent; +- an approved translation revision is immutable and rollback selects a prior immutable revision; +- draft translation item UPSERT never creates duplicate `(translation_resource_id, locale_code, screen_key)` items within one revision. ### Database integration tests -Run against real PostgreSQL 18.6 or a later supported 18.x patch. Validate migrations, RLS, temporal constraints, indexes, transaction isolation, outbox atomicity, lock behavior, partition pruning, backup, and restore. +Run against real PostgreSQL 18.6 or a later supported 18.x patch. Validate migrations, RLS, temporal constraints, indexes, transaction isolation, outbox atomicity, lock behavior, partition pruning, translation-resource item-level UPSERT/idempotency, backup, and restore. ### Contract tests -Validate OpenAPI, AsyncAPI, CloudEvents, JSON Schema, generated clients, Problem Details, pagination cursors, idempotency, ETags, provider adapters, and backward compatibility. +Validate OpenAPI, AsyncAPI, CloudEvents, JSON Schema, generated clients, Problem Details, pagination cursors, idempotency, ETags, provider adapters, translation screen-key/revision responses, and backward compatibility. ### Fuzz tests -Target parsers, identifiers, rich text, import payloads, webhook signatures, cursor decoding, date intervals, currency input, CSV/Office exports, and event envelopes. +Target parsers, identifiers, rich text, import payloads, webhook signatures, cursor decoding, date intervals, currency input, CSV/Office exports, translation keys/locale tags, and event envelopes. ### Security tests @@ -74,18 +76,20 @@ A model feature cannot pass through ordinary snapshot tests alone. Required evid Arbitrary weights and rule-of-thumb thresholds are prohibited. -### UX and accessibility tests +### UX, accessibility, and locale tests - keyboard-only journeys; - screen-reader semantics; -- focus order and restoration; +- focus order, focus visibility, focus-not-obscured, and restoration; - touch target and mobile viewport; - high zoom and text reflow; - reduced-motion preference; -- Korean and English copy expansion; -- loading, empty, partial, stale, conflict, denied, offline, and error states; +- `ko/en/ja/zh/vi/es/de/fr` locale matrix covering CJK, expansion, wrapping, font fallback, dates, names, addresses, currencies, time zones, sorting, and validation copy; +- DB-backed translation revision fetch/cache/invalidation, review/approval/deploy/rollback, and no-full-browser-catalog assertions; +- loading, empty, partial, stale, conflict, denied, permission, offline, and error states; - exact-value tables and print/PDF output for charts; -- Storybook interaction and accessibility tests. +- Storybook interaction, locale, responsive, and accessibility tests; +- screenshot review for desktop, tablet, mobile, typography/color, forms/feedback, navigation, charts/data, and action edges. ### End-to-end buyer journeys @@ -96,13 +100,14 @@ Arbitrary weights and rule-of-thumb thresholds are prohibited. 5. Resolve a complaint and connect remedy, outcome, and follow-up. 6. Submit a data-access case and inspect a purpose-limited export. 7. Attempt cross-tenant reads, writes, search, graph traversal, export, and model access. -8. Restore the system and prove data, outbox, projection, and key consistency. +8. Restore the system and prove data, outbox, projection, translation revision, and key consistency. +9. Repeat buyer-visible journeys in every release locale with realistic expansion and CJK-sensitive content. ## 4. Realistic fixtures Fixtures represent multi-stakeholder B2B relationships, account hierarchy, role changes, former employees, multiple opportunities, delayed interactions, conflicting commitments, complaints, multiple currencies, duplicated events, malformed imports, and multilingual text. Names and organizations are synthetic. -Synthetic data is labeled and never used as evidence of customer accuracy or product-market fit. +Synthetic data is unit-test-only and never used as evidence of customer accuracy, product-market fit, production load behavior, or buyer-facing latency. ## 5. Temporal validation @@ -119,19 +124,20 @@ Tests use both business time and recorded time. Cases include: ## 6. Performance and load -A k6 or equivalent end-to-end suite exercises asynchronous and synchronous workflows. Initial engineering acceptance targets are: +Realistic k6 end-to-end suites exercise every buyer-facing page and asynchronous workflow. Every buyer-facing page has a release target of **p95 ≤ 20 ms** at the declared ready-to-interact boundary under the documented release benchmark profile. The denominator includes all measured page samples; slow samples are not excluded, the dataset is not shrunk to pass, and warmup/cache state must reflect the declared production profile. + +The harness records request, database/query, render, bundle/heap/DOM/hydration/main-thread/GC, network, connection-pool, and runtime evidence where applicable. If a page misses the target, the causal algorithm/query/I/O/render/runtime is profiled and repaired; sampling or thresholds are not weakened. Search or deep exploration that cannot fit the interactive budget becomes explicitly bounded/paginated or asynchronous. + +Additional throughput and asynchronous contracts are: | Workload | Target | |---|---:| -| account summary read | p95 ≤ 300 ms at 200 concurrent users | -| account timeline, 1,000 entries | p95 ≤ 700 ms | -| relationship neighborhood, depth 2 | p95 ≤ 1.5 s with bounded result set | -| optimistic update | p95 ≤ 500 ms | -| event ingestion | sustained 1,000 events/s per deployment profile | +| every buyer-facing page | p95 ≤ 20 ms | +| event ingestion | sustained 1,000 events/s per declared deployment profile | | queue admission under saturation | bounded response with no silent drop | -| export request | acknowledgement ≤ 500 ms; asynchronous completion | +| export/import/model/connector request | non-blocking acknowledgement with durable job status/cancellation | -These are release targets, not current performance claims. Tests record hardware, dataset size, connection pools, cache state, and commit SHA. +Tests record hardware, CPU/GPU path when relevant, container limits, dataset size, PostgreSQL/app/shm configuration, connection pools, cache state, browser/runtime versions, and exact commit SHA. Docker, Podman, and Colima compatibility is exercised without using project-name overrides except for test isolation. ## 7. Recovery testing @@ -140,6 +146,7 @@ These are release targets, not current performance claims. Tests record hardware - schema compatibility and migration replay; - outbox/inbox deduplication after restore; - projection rebuild from canonical data; +- translation-resource revision and active-deployment restoration; - object-store artifact reconciliation; - lost worker and connection interruption; - partial provider outage; @@ -153,7 +160,8 @@ Suggested required checks: Contract and documentation validation Rust format, lint, unit, property, and doc tests PostgreSQL integration and migration rehearsal -Frontend lint, typecheck, unit, Storybook, and E2E +Frontend lint, typecheck, unit, Storybook, locale, and E2E +k6 realistic buyer-page performance gate Coverage and documentation gate SAST and secret scan Dependency review and vulnerability scan @@ -163,8 +171,8 @@ Supply-chain SBOM and provenance Production-readiness evidence ``` -Every check runs on the exact PR head or merge-result tree specified by branch policy. Prior-head success is not current evidence. +Every check runs on the exact PR head or merge-result tree specified by branch policy. Prior-head success is not current evidence. A queued, skipped, startup-failed, or unmaterialized required job is not passing evidence. ## 9. Test-evidence manifest -A release manifest records command, environment, commit, dependency lock hash, database version, browser version, test counts, coverage denominators, skipped tests, benchmark profile, artifact hashes, and reviewer identity. +A release manifest records command, environment, commit, dependency lock hash, database version, browser/runtime version, test counts, coverage denominators, skipped tests, locale matrix, benchmark profile, complete performance denominator, artifact hashes, and reviewer identity. From 73f9b0695115b92774a3137bcfaff9884d36f668 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 20:27:41 +0900 Subject: [PATCH 79/87] docs(gap): reconcile commercialization performance and i18n gaps --- docs/product-technical-gap-baseline.md | 185 +++++++++++++++---------- 1 file changed, 113 insertions(+), 72 deletions(-) diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index a375b01..1ca6339 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,149 +1,190 @@ # ELUNVERA Product–Technical Gap Baseline -- **Baseline version:** 0.3 +- **Baseline version:** 0.4 - **Observed date:** 2026-09-02 - **Repository:** `ContextualWisdomLab/ELUNVERA` - **Target integration branch:** `main` -- **Evidence scope:** live repository metadata plus this documentation and source-license change +- **Evidence scope:** live repository/PR state plus this Draft foundation's PRD, TRD, architecture, data model, API/event contracts, UX, test strategy, ADRs, and source-license proposal ## 1. Executive status -ELUNVERA is a newly created public, non-fork repository whose protected `main` branch remains at the bootstrap revision while this Draft foundation is reviewed. The foundation branch establishes product and technical design contracts, repository validation, a public documentation source, and a proposed Apache-2.0 grant for ContextualWisdomLab-authored source/documentation only. It still contains no production runtime, database migration, customer deployment, benchmark, or immutable release. +ELUNVERA is a public, non-fork, very-early-stage repository whose protected `main` branch remains at the bootstrap revision while this Draft foundation is reviewed. The foundation branch establishes product and technical design contracts, repository validation, a public documentation source, and a proposed Apache-2.0 grant for ContextualWisdomLab-authored source/documentation only. It still contains no production runtime, database migration, customer deployment, benchmark, or immutable release. **Current honest classification:** `design baseline / pre-implementation`. -The repository must not be described as alpha, beta, production-ready, secure, compliant, scalable, accessible, or commercially validated until the corresponding implementation and evidence exist. The proposed repository source license permits commercial use if integrated as written, but is not evidence that a sellable product or a future dependency set is commercially ready. +The repository must not be described as alpha, beta, production-ready, secure, compliant, scalable, accessible, internationally complete, or commercially validated until the corresponding implementation and evidence exist. Current exact-head workflow/review status belongs to the live PR evidence and must be re-fetched after every push; queued, skipped, startup-failed, or predecessor-head results are not passing evidence. -## 2. Product definition established by this baseline +## 2. Product definition and DDD boundary -ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence system of record. It owns tenant-scoped commercial account, party, relationship, interaction metadata, commitment, opportunity, customer outcome, complaint, satisfaction observation, privacy workflow, audit, and provenance facts. +ELUNVERA is an evidence-centered enterprise CRM and relationship-intelligence system of record. Its **core subdomain** is governed commercial relationship truth and action: tenant-scoped commercial accounts, parties, relationships, interactions, commitments, opportunities, customer outcomes, complaints, privacy workflow, audit, and evidence-linked human decisions. -It deliberately does not own identity, email/calendar/file hosting, generalized project execution, billing, ontology/catalog, or LLM routing. Those capabilities are consumed from CWL products through versioned contracts. +Supporting subdomains include authorization-context consumption, integration mapping/outbox, search projections, model evidence, and ELUNVERA-owned UI translation resources. Generic capabilities such as identity, LLM routing, ontology/catalog publication, retrieval fusion, message threading, and general work execution remain with their released ContextualWisdomLab owners and are consumed only through versioned contracts and ACLs. + +### Bounded contexts and context map + +```text +Keyverse ──ACL──> Authorization Context + │ + v +Account Registry <──> Party Registry <──> Relationship Registry + │ │ │ + ├──────────────> Interaction Timeline <──┤ + ├──────────────> Commitment Registry <───┤ + └──────────────> Opportunity Management ─┤ + Customer Outcomes / Complaints + │ + Privacy Rights <─────────────┤ + Audit & Provenance <─────────┤ + Translation Resources ───────┤ + v + rebuildable Search / Model Evidence / Integration Outbox + │ │ │ + v v v + RankWeave contextual-orchestrator released provider/CWL APIs +``` + +The aggregate boundary is the smallest transactionally consistent business object; ELUNVERA does not create a shared-kernel monolith across account, relationship, opportunity, privacy, translation, or external products. External/legacy dependencies are isolated behind ACLs. Translation resource publication is separate from ontology label publication and never changes product-domain ubiquitous language. ## 3. Traceability matrix | Product concern | Product requirement | Technical decision | Contract/data | Current implementation | Required next evidence | |---|---|---|---|---|---| -| Account continuity | PRD FR-001–006 | modular account registry | `commercial_account`, account APIs | none | Rust API, migration, E2E | -| Stakeholder history | FR-010–015 | first-class bitemporal relationship | relationship tables/events | none | temporal/property/DB tests | -| Interaction context | FR-020–024 | metadata projection, source refs | interaction/commitment APIs | none | naruon/ThreadWeave contract tests | -| Opportunity truth | FR-030–036 | versioned process and immutable snapshots | opportunity tables/events | none | stage and exact-money tests | -| Complaints/outcomes | FR-040–044 | structured complaint/outcome modules | complaint/outcome APIs | none | ISO-aligned E2E evidence | -| Search/intelligence | FR-050–054 | rebuildable projection and model claims | search/model jobs | none | retrieval and unsupported-claim tests | +| Account continuity | PRD FR-001–005 | modular account registry | `commercial_account`, account APIs | none | Rust API, migration, E2E | +| Stakeholder history | FR-010–013 | first-class bitemporal relationship | relationship tables/events | executable prototype exists only on stacked PR #1 | temporal/property/DB tests after foundation integration | +| Interaction context | FR-020–024 | metadata projection, source refs | interaction/commitment APIs | none | released provider/CWL contract tests | +| Opportunity truth | FR-030–035 | versioned process and immutable snapshots | opportunity tables/events | none | stage and exact-money tests | +| Complaints/outcomes | FR-040–043 | structured complaint/outcome modules | complaint/outcome APIs | none | ISO-aligned E2E evidence | +| Search/intelligence | FR-050–053 | rebuildable projection and model claims | search/model jobs | none | retrieval and unsupported-claim tests | | Privacy/rights | FR-060–064 | purpose-aware field selection | rights/retention models | none | PIPA/GDPR profile review and E2E | +| Administration | FR-070–073 | versioned configuration and capability adapters | admin/provider contracts | none | item-level idempotency/replay tests | | Tenant isolation | NFR security | Keyverse + RLS | auth context | none | adversarial cross-tenant suite | | Availability | NFR reliability | operability and restore contracts | health/SLO/runbook | none | live telemetry and restore rehearsal | -| Accessibility | NFR UX | WCAG 2.2 AA + Storybook | UX and design system | none | Figma, UI, AT audit | +| Page performance | NFR-010–013 | async long work; profile causal page path | k6 buyer-page evidence | none | realistic every-page p95 ≤ 20 ms | +| Accessibility | NFR-030–033 | WCAG 2.2 AA + Storybook | UX/design system | none | Figma, screenshots, AT audit | +| Internationalization | NFR-032 | DB-backed versioned resources; screen-key delivery | translation revision contract | none | ko/en/ja/zh/vi/es/de/fr Storybook/E2E | | Scientific scoring | P-05 | Rust + TEPP/fast-mlsirm, no heuristics | model artifact/claim | none | validation study and model release gate | -## 4. Gap register +## 4. Commercialization gap register ### G-001 Repository governance -**Current evidence:** `main` and `develop` exist at the same bootstrap revision, but `main` is the canonical protected integration branch. The organization default-branch ruleset applies ordinary review protection, including qualifying approval and unresolved-thread protection. This Draft PR now targets `main`; its permanent document-contract workflow and CodeRabbit configuration were repaired to include `main` after the retarget. - -**Remaining gap:** exact-head required workflow completion, current semantic review, release-policy evidence, and any repository-specific ownership controls not supplied by the organization baseline remain unproven. `develop` is not a release authority. - -**Risk:** stale branch assumptions or predecessor-head evidence can bypass the intended integration contract even when organization protection exists. - -**Action:** keep `main` canonical; require exact-head document/contract and organization checks plus qualifying independent review; preserve the ruleset rather than weakening it; add repository-specific ownership/release controls only when their responsibility is not already centrally supplied. - -**Exit evidence:** live ruleset snapshot plus a successful ordinary protected PR on the unchanged exact head. +**Owner:** ELUNVERA + organization control plane where causal. +**Current evidence:** `main` and `develop` exist at the same bootstrap revision; `main` is canonical protected integration authority. The Draft foundation targets `main`; document-contract CI validates canonical branch authority and now also fails closed on performance/i18n contract drift. +**Gap:** exact-head required workflow completion, current semantic review, release-policy evidence, and any repository-specific ownership controls not centrally supplied remain unproven. +**Action:** preserve protected `main`, exact-head checks, independent review, and central reusable workflows; never weaken a leaf gate to compensate for hosted-runner or workflow-materialization failure. +**Exit evidence:** unchanged exact-head required checks plus ordinary protected integration. ### G-002 Executable Rust foundation -**Gap:** no Cargo workspace or production code. -**Risk:** architecture and quality goals are unverified. -**Action:** implement the M1 Rust workspace through TDD, beginning with identity/tenant context and account/party/relationship kernel. -**Exit evidence:** build, lint, unit/property/integration, coverage, and doc reports. +**Owner:** ELUNVERA. +**Gap:** protected foundation has no Cargo workspace or production code. +**Action:** after foundation integration, build the smallest Rust domain/API slice test-first. Reconcile stacked PR #1 rather than discarding its valid Relationship Activation delta. +**Exit evidence:** Rust build/lint/unit/property/doc/coverage results on exact source. ### G-003 PostgreSQL lifecycle -**Gap:** no migration, RLS, temporal constraint, pool, backup, or restore. -**Risk:** canonical truth and isolation are conceptual only. -**Action:** pin supported PostgreSQL 18.x, create 3NF migrations, RLS, temporal constraints, outbox, clean/upgrade rehearsal, encrypted backup, and restore validation. -**Exit evidence:** PostgreSQL integration and restore artifacts. +**Owner:** ELUNVERA. +**Gap:** no migration, RLS, temporal constraint, pool, item-level UPSERT implementation, hot-lock evidence, backup, or restore. +**Action:** pin supported PostgreSQL 18.x, create 3NF multi-word persistence objects, RLS, temporal constraints, outbox, explicit item-level UPSERT/idempotency, contention tests, clean/upgrade rehearsal, encrypted backup, and restore validation. +**Exit evidence:** PostgreSQL integration, lock/contention, migration, backup, and restore artifacts. ### G-004 Keyverse integration -**Gap:** no OIDC/JWKS/SCIM implementation. -**Risk:** no authenticated remote operation is safe. -**Action:** implement exact issuer/audience/token validation and immutable authorization context; separate CRM party identity from authentication subject. -**Exit evidence:** negative token and tenant tests. +**Owner:** Keyverse for released identity contract; ELUNVERA for product-owned login/signup/recovery UI and ACL. +**Gap:** no OIDC/JWKS/SCIM implementation or product authentication forms. +**Action:** consume only immutable released Keyverse contracts; implement exact issuer/audience/token validation and immutable authorization context; keep CRM party identity distinct from authentication subject. +**Exit evidence:** negative token, tenant, recovery, CSS/action-edge, and integration tests. ### G-005 Account and relationship UX -**Gap:** no Figma file, design tokens, Storybook, UI, screenshots, or accessibility evidence. -**Risk:** product remains a database design rather than a usable CRM. -**Action:** create the three-band account experience in Figma, record file ID in ADR, implement shared tokens and Storybook edge states, then E2E and AT audit. -**Exit evidence:** reviewed Figma, screenshots, interaction tests, WCAG report. +**Owner:** ELUNVERA. +**Gap:** no Figma file, product-owned reusable component system, Storybook, production UI, screenshots, or accessibility evidence. +**Action:** create the three-band account experience in Figma, record file ID in ADR, implement design tokens/product-owned components and Storybook normal/loading/empty/error/permission/responsive/interaction states, then run full screenshot/E2E/AT audit. +**Exit evidence:** reviewed Figma, Storybook, screenshots, interaction tests, and WCAG evidence. ### G-006 Provider and CWL contracts -**Gap:** adapters and consumer contracts do not exist. -**Risk:** integrations may duplicate authority or leak PII. -**Action:** implement one bounded vertical at a time, starting with Keyverse and then customer-controlled interaction metadata; publish provider/consumer fixtures in both repositories. -**Exit evidence:** conformance, duplicate/reorder, outage, and reconciliation tests. +**Owner:** canonical supplier for reusable defects; ELUNVERA for consumer ACLs/adapters. +**Gap:** adapters and consumer contracts do not exist. +**Action:** consume only released immutable contracts. For an immature owner, use a port/ACL/feature flag/test double until owner RED→fix→GREEN→immutable release; never copy owner source, read owner DB, or bind to a temporary branch. +**Exit evidence:** supplier release plus consumer conformance, duplicate/reorder, outage, and reconciliation tests. ### G-007 Privacy operation -**Gap:** purpose, rights, retention, hold, export, and disposition are documentation only. -**Risk:** product cannot responsibly process production customer data. -**Action:** implement policy decision receipts and complete rights/disposition workflows before production PII. -**Exit evidence:** jurisdiction-reviewed policies and realistic rights tests. +**Owner:** ELUNVERA. +**Gap:** purpose, rights, retention, hold, export, and disposition are documentation only. +**Action:** implement policy decision receipts and complete rights/disposition workflows before production PII; use least privilege, encryption, field selection, purpose limitation, and audit rather than destructive masking where masking breaks legitimate work. +**Exit evidence:** jurisdiction-reviewed policy plus realistic rights and non-masking-protection tests. ### G-008 Security and supply chain -**Gap:** no executable-product CI, SAST, secret scan, dependency review, SBOM, provenance, signatures, or penetration test evidence yet. -**Risk:** no trustworthy runtime artifact exists. -**Action:** use central `.github` reusable workflows, exact pins, minimal permissions, and a signed release pipeline as executable code is introduced. -**Exit evidence:** current-head checks and signed release candidate. +**Owner:** `.github` for reusable controls; ELUNVERA for thin callers/product evidence. +**Gap:** no executable-product CI artifact, dependency/SBOM/provenance/signature, penetration evidence, or production runtime exists. +**Action:** use released central workflows, exact pins, minimal permissions, fail-closed dependency/security gates, and signed release pipeline when runtime arrives. +**Exit evidence:** current-head checks, SBOM/provenance, signatures, and tested release candidate. ### G-009 Operability -**Gap:** no health endpoints, telemetry, SLO, alert, capacity, incident, or recovery runtime. -**Risk:** failures and data loss cannot be detected or managed. -**Action:** implement liveness/startup/readiness, OTLP, low-cardinality metrics, queue/backpressure, capacity benchmark, runbooks, and rehearsal. -**Exit evidence:** SLO dashboard and operational drill receipts. +**Owner:** ELUNVERA. +**Gap:** no health endpoints, telemetry, SLO, alert, capacity, incident, compose deployment, or recovery runtime. +**Action:** implement liveness/startup/readiness, async cancellation, OTLP, low-cardinality metrics, queue/backpressure, Compose for Docker/Podman/Colima, measured hardware tuning, runbooks, and recovery rehearsal. Verify `close_connection` assumptions in any framework/adapter before relying on them. +**Exit evidence:** SLO dashboard, realistic capacity run, and operational drill receipts. ### G-010 Model governance and measurement -**Gap:** no model, dataset, benchmark, validity, fairness, or calibration evidence. -**Risk:** “relationship intelligence” could become ungrounded profiling. -**Action:** release no score until a specific outcome and population are defined; validate through contextual-orchestrator plus TEPP/fast-mlsirm where appropriate; preserve evidence, uncertainty, review, and appeal. -**Exit evidence:** model card, evaluation report, recovery/calibration metrics, monitoring. +**Owner:** ELUNVERA model domain plus released TEPP/fast-mlsirm/contextual-orchestrator contracts. +**Gap:** no model, dataset, benchmark, validity, fairness, or calibration evidence. +**Action:** release no score until outcome/population/sampling design/error target/failure denominator are defined; keep production numerical computation in Rust, model multilevel/multiple-membership/time structure where relevant, and prohibit heuristic weights. +**Exit evidence:** model card, true-parameter recovery/validation, calibration/error analysis, and monitoring. ### G-011 Commercial and legal readiness -**Proposed slice on this Draft branch:** ContextualWisdomLab-authored ELUNVERA source and documentation are proposed for an explicit Apache License 2.0 repository grant under ADR-0013. The root `LICENSE` and documentation express that boundary, but ADR-0013 remains `Proposed` until ordinary protected-branch integration preserves the decision and its validation evidence. The grant does not imply trademark registration and does not relicense third-party material. - -**Remaining gap:** no trademark registration evidence, terms, DPA, support policy, pricing, entitlement, billing integration, or dependency/asset license inventory for a future executable distribution. -**Risk:** a licensed public design repository is still not a sellable or legally complete product, and future imported components may carry independent obligations. -**Action:** after foundation integration, complete trademark/legal review, product terms/DPA/support model, dependency and asset provenance inventory, deployment/support offer, and Billing Control Plane integration after core product evidence exists. -**Exit evidence:** protected-main license/ADR integration plus reviewed commercial/legal package and exact distributable dependency/SBOM/license/attribution evidence. +**Owner:** ELUNVERA/product/legal. +**Current proposed slice:** Apache License 2.0 for ContextualWisdomLab-authored source/docs under Proposed ADR-0013. +**Gap:** no trademark evidence, terms, DPA, support policy, pricing, entitlement, billing integration, dependency/asset inventory, or sellable deployment. +**Action:** complete legal/commercial package only after protected foundation/runtime evidence. +**Exit evidence:** protected-main license/ADR integration plus reviewed commercial package and exact distributable SBOM/license/attribution evidence. ### G-012 Product validation -**Gap:** no customer interviews, usability data, activation, retention, willingness-to-pay, or outcome study. -**Risk:** engineering completeness may not create buyer value. -**Action:** validate the account-preparation, opportunity-review, and complaint-recovery verticals with target users and measure time-to-context, evidence coverage, correction rate, and workflow outcome. +**Owner:** ELUNVERA product. +**Gap:** no customer interviews, usability data, activation, retention, willingness-to-pay, or outcome study. +**Action:** validate account-preparation, opportunity-review, and complaint-recovery jobs with target users and measure time-to-context, evidence coverage, correction rate, workflow outcome, and willingness-to-pay. **Exit evidence:** research protocol and anonymized findings. +### G-013 Every-page performance contract + +**Owner:** ELUNVERA. +**Evidence:** PRD/TRD/Test Strategy now require realistic every-buyer-page k6 p95 ≤ 20 ms; the permanent document-contract workflow prevents regression to weaker page targets. +**Gap:** no runtime exists, so no latency claim is proven. +**Action:** when UI/runtime starts, measure full declared page denominator including DB/query/render/bundle/heap/DOM/hydration/main-thread/GC and cold/cache profile. Fix causal algorithm/query/I/O/render/runtime/Rust hot path; never shrink data, omit slow samples, or use unrealistic warmup. +**Exit evidence:** exact-head k6 artifacts for every buyer-facing page at p95 ≤ 20 ms. + +### G-014 Translation-resource authority and eight-locale delivery + +**Owner:** ELUNVERA unless a separately released reusable CWL translation product later proves common ownership. +**Evidence:** PRD/TRD/UX/Test Strategy now specify `ko/en/ja/zh/vi/es/de/fr`, DB-backed versioned translation resources, screen-key-scoped server/native fetch/cache, review/approval/deploy/rollback, and separation from ontology labels. +**Gap:** no schema/API/admin UI/cache/locale assets or Figma/Storybook/E2E evidence exists. +**Action:** implement `translation_resource`, `translation_revision`, and `translation_text` in 3NF with immutable approved revisions, explicit draft item UPSERT, revision-aware cache invalidation, product-owned admin UI, and locale-specific interaction/screenshot tests. +**Exit evidence:** migration/API/admin UI + eight-locale Storybook/E2E + rollback and cache-invalidation receipts. + ## 5. Highest-leverage implementation order ```text canonical-main governance and foundation integration +→ reconcile stacked Relationship Activation delta without loss → identity and tenant boundary → PostgreSQL account/party/relationship kernel → audit, outbox, idempotency, temporal APIs -→ three-band account UX +→ translation-resource authority + eight-locale component contract +→ three-band account UX + every-page k6 p95 ≤ 20 ms → opportunity and commitment vertical → complaints, outcomes, and privacy workflows -→ bounded CWL integrations +→ bounded released CWL integrations → validated relationship intelligence → scale, security, accessibility, recovery, and commercial GA ``` ## 6. Release truth -This Draft documentation baseline addresses the absence of a coherent product definition, implementation contract, proposed public repository source-license decision, and source-documentation navigation. It closes none of the runtime, security, privacy, accessibility, model-validity, scalability, operational, broader legal/commercial, or market-validation gaps listed above, and it does not mark a decision Accepted merely because it exists on an unmerged branch. No release exists until an exact protected executable source and its required artifact, dependency, SBOM, provenance, review, and operational evidence are independently established. +This Draft documentation baseline fixes contradictory weak latency and two-locale requirements by making the current commercialization contract executable in document CI. It still closes none of the runtime, PostgreSQL, security, privacy, accessibility, model-validity, scalability, operational, broader legal/commercial, or market-validation gaps above. No release exists until an exact protected executable source and its required artifact, dependency, SBOM, provenance, review, performance, locale, accessibility, security, and operational evidence are independently established. From 7c0098c4d0fccc2994ac5594ac4a141f6debc952 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 20:28:03 +0900 Subject: [PATCH 80/87] docs(changelog): record commercialization contract repair --- CHANGELOG.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53dbc92..df5af93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ The format follows Keep a Changelog principles, and versioning will begin when t - Initial product-technical gap baseline and phased implementation plan. - Public documentation landing and exact-cased DeepWiki entry point. - Apache License 2.0 grant for ContextualWisdomLab-authored ELUNVERA source and documentation, with trademark and third-party rights kept separate. +- Proposed eight-locale (`ko/en/ja/zh/vi/es/de/fr`) product contract with DB-backed versioned translation-resource authority, review/approval/deploy/rollback semantics, screen-key-scoped delivery, and separation from ontology labels. +- Proposed realistic k6 every-buyer-page p95 ≤ 20 ms release contract, with full measured denominator and causal profiling requirements. ### Fixed @@ -27,11 +29,14 @@ The format follows Keep a Changelog principles, and versioning will begin when t - Retargeted the Draft foundation to canonical protected `main`, aligned document-contract and review automation with that base, and corrected stale `develop` navigation/governance claims. - Returned ADR-0013 to `Proposed` while the foundation remains unmerged; protected integration is required before the decision may be marked `Accepted`. - Aligned AGENTS, contributing guidance, PRD, roadmap, and implementation plan/spec branch authority with canonical protected `main`; stacked work may target only its verified prerequisite branch, and document-contract CI now guards that authority against drift. +- Replaced the earlier 300–1500 ms page targets and two-locale release assumptions with the current commercialization contract; document-contract CI now fails closed if PRD/TRD/UX/Test Strategy regress from the p95 ≤ 20 ms and eight-locale requirements. +- Added DDD ownership and persistence expectations for `translation_resource`, `translation_revision`, and `translation_text`, including immutable approved revisions and explicit draft item-level UPSERT semantics. ### Security - Defined fail-closed tenant isolation, purpose-aware authorization, immutable audit, model provenance, controlled egress, and customer-data disclosure boundaries. +- Required model-backed GitHub Actions to consume the released contextual-orchestrator gateway through `orchestrator/free` only, with no workflow-selected provider/model/paid fallback. ### Notes -- No runtime, database schema, deployment artifact, or release exists in this baseline. +- No runtime, database schema, deployment artifact, customer performance measurement, eight-locale implementation, or release exists in this baseline. The new contracts are requirements, not evidence of conformance. From d7cd411e73ede10ecd0e77844ed716aed1193684 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Wed, 2 Sep 2026 20:36:55 +0900 Subject: [PATCH 81/87] chore(manifest): reseal commercialization contract evidence --- manifest.json | 359 +------------------------------------------------- 1 file changed, 1 insertion(+), 358 deletions(-) diff --git a/manifest.json b/manifest.json index da0dd3c..635add5 100644 --- a/manifest.json +++ b/manifest.json @@ -1,358 +1 @@ -{ - "schema_version": "1.0", - "product": "ELUNVERA", - "generated_at": "2026-09-02T10:06:00Z", - "algorithm": "SHA-256", - "self_excluded": true, - "file_count": 58, - "files": [ - { - "path": ".coderabbit.yaml", - "sha256": "efe46b993fae145eeaa2b2fb2cf0c302000c6373e5246c8e54bf330d636f4e2b", - "size_bytes": 112, - "line_count": 7 - }, - { - "path": ".cwl/data-management.yaml", - "sha256": "28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671", - "size_bytes": 1727, - "line_count": 48 - }, - { - "path": ".github/pull_request_template.md", - "sha256": "d7584adf5eb9866449fc5f38dc490422bf23de31ae75e1bdb385265c68122d15", - "size_bytes": 1064, - "line_count": 38 - }, - { - "path": ".github/workflows/document-contracts.yml", - "sha256": "7ccb26e8cf0c6018a3286b9454a447a6f858b095a0f5a7e89937709eab13618f", - "size_bytes": 8296, - "line_count": 176 - }, - { - "path": "AGENTS.md", - "sha256": "6c97e76c8ec1da4d30b82a1759755bae11018c132ca0fd29d7dfc803b55006a1", - "size_bytes": 4152, - "line_count": 84 - }, - { - "path": "CHANGELOG.md", - "sha256": "6a7c7b82208a23ac493edb4df481c95b77fbeef1551856bb39a941f9ea054214", - "size_bytes": 2536, - "line_count": 37 - }, - { - "path": "CLAUDE.md", - "sha256": "67f513ae368f851201f50b6f732f444a648b3a940ca261411edbbc4c9f1ab223", - "size_bytes": 1684, - "line_count": 34 - }, - { - "path": "CONTRIBUTING.md", - "sha256": "5aee2d583ac082626a59cca4a832715ab6c9ef0e406ae48c7976887c71a74127", - "size_bytes": 1696, - "line_count": 43 - }, - { - "path": "LICENSE", - "sha256": "b7fa79459ac09645fd5bed5363852ba8759fa6deeb972d02f09fb0dc50fef586", - "size_bytes": 11290, - "line_count": 192 - }, - { - "path": "README.md", - "sha256": "3c65f74b492dfe6ae8e06eedd23a5ffde397d06b751d10a29f464c0621b77b04", - "size_bytes": 5471, - "line_count": 84 - }, - { - "path": "SECURITY.md", - "sha256": "4bfbb000844294b22ff9882211ee0a57b38e637002847cfdde8818b9276851eb", - "size_bytes": 1091, - "line_count": 32 - }, - { - "path": "docs/API_CONTRACT.md", - "sha256": "82f5d44989a1d7000dd586dde95ad71e00f52aec05d053bacbebd5f22988cfb5", - "size_bytes": 8811, - "line_count": 226 - }, - { - "path": "docs/ARCHITECTURE.md", - "sha256": "f4e39936636d48ed0d4d1c21f02562860be1af19fe8eec2d75e1d9049c30861f", - "size_bytes": 9402, - "line_count": 250 - }, - { - "path": "docs/DATA_MODEL.md", - "sha256": "3bbfe050809c960406514ff3ad0d8a273dc84b80c377189fd23f2c80f40da10a", - "size_bytes": 15101, - "line_count": 504 - }, - { - "path": "docs/OPERABILITY.md", - "sha256": "1c725823885df063bb43d8d9e4d80258ed6b9ef5029bb97cdf5100f7ec7dc80d", - "size_bytes": 7003, - "line_count": 151 - }, - { - "path": "docs/PRD.md", - "sha256": "95576c4d9b20bbc95ed355e5771f7b429d1346cd721b1224c007db1cabd4ae65", - "size_bytes": 22099, - "line_count": 366 - }, - { - "path": "docs/PRIVACY.md", - "sha256": "0599406e743af7c561208da8ad505c704ea585cebeb941444d221584aad5e004", - "size_bytes": 6899, - "line_count": 141 - }, - { - "path": "docs/ROADMAP.md", - "sha256": "3e94efa42e1553428dd90c8bd6b298b114a1af8188faa0968f690b6dd4f9a486", - "size_bytes": 3415, - "line_count": 84 - }, - { - "path": "docs/SECURITY.md", - "sha256": "d10ae9757a7233b9ce73eaa038f75939d22da4709ac6db7ee16fe4b291bd64dd", - "size_bytes": 8100, - "line_count": 174 - }, - { - "path": "docs/STORYBOARD.md", - "sha256": "c9e2d38ca25e024a7599afeff711187be272cebc7c51a9ca603846bf33bda392", - "size_bytes": 2775, - "line_count": 41 - }, - { - "path": "docs/STORYBOOK_INVENTORY.md", - "sha256": "e210ed7072720bef3b825f226419ff25dd68ee412d5272f0e5d51234b8ea4fe1", - "size_bytes": 2354, - "line_count": 99 - }, - { - "path": "docs/TEST_STRATEGY.md", - "sha256": "b0f24b7fe2518c2d9e214868e7f7fe3189cc49307b988723dec5d939f82c9af0", - "size_bytes": 7302, - "line_count": 170 - }, - { - "path": "docs/THREAT_MODEL.md", - "sha256": "1dc10db1d5fb0a314e25cd78c9bb1ed90b40315dbb3a32d387c2b5758910100f", - "size_bytes": 7043, - "line_count": 132 - }, - { - "path": "docs/TRD.md", - "sha256": "c069df7a0d0f2a955eefeea39b87004ab351a75cae6dba4e65c29856f162af78", - "size_bytes": 15094, - "line_count": 345 - }, - { - "path": "docs/UML.md", - "sha256": "882a33a38bda7494e370f4135b9a3d7c5d3cf054d47cc511f3813eb046916d0c", - "size_bytes": 3165, - "line_count": 115 - }, - { - "path": "docs/USER_STORIES.md", - "sha256": "cdc8e1a2b74d7821279dfe0f07dda2d25b9bae088a720b9a6fb19270af36208c", - "size_bytes": 3184, - "line_count": 37 - }, - { - "path": "docs/USE_CASES.md", - "sha256": "4df536423c1796793edd35c200b624e6ec1daa87adf6ace9748608f24c254022", - "size_bytes": 4357, - "line_count": 69 - }, - { - "path": "docs/UX_SPEC.md", - "sha256": "ed3dc4b9738f5a0fbfa2f8176379a14c4b3a222b7b305c1fc31ea61e257115be", - "size_bytes": 6609, - "line_count": 171 - }, - { - "path": "docs/VALIDATION_REPORT.md", - "sha256": "71b913ecac5bea2f94d10933c959bff0c0ba28110ee3be087a8578db08391ab8", - "size_bytes": 2895, - "line_count": 56 - }, - { - "path": "docs/WIREFRAMES.md", - "sha256": "e989815acd882701ff2737036ae6f278b5a01c45081204c3c65c33c9dc0e4f01", - "size_bytes": 4526, - "line_count": 81 - }, - { - "path": "docs/adr/0001-product-boundary.md", - "sha256": "86f3513bdfa2c2c8766c6c2afdbec7b099778982e9246efe729b5d9f76da3e24", - "size_bytes": 1151, - "line_count": 21 - }, - { - "path": "docs/adr/0002-modular-monolith.md", - "sha256": "0415bc80db206f5581c758a83f09abe14bfa5e45e76fbc2b38b7bb958d2342bb", - "size_bytes": 955, - "line_count": 21 - }, - { - "path": "docs/adr/0003-keyverse-identity.md", - "sha256": "10fccb512eff2665cf0b43ef5bbef1cdf4501962e0ae353777f131a75552c309", - "size_bytes": 865, - "line_count": 21 - }, - { - "path": "docs/adr/0004-bitemporal-truth.md", - "sha256": "d7d85c1fefeed397e417653a46e1ddd2d9505740f9369d2f16769dac344d373c", - "size_bytes": 875, - "line_count": 21 - }, - { - "path": "docs/adr/0005-first-class-relationships.md", - "sha256": "1130b14f9f448d3aba40086cb1355683c0d5b4891368706c860b41e5467a5852", - "size_bytes": 848, - "line_count": 21 - }, - { - "path": "docs/adr/0006-provider-neutral-integrations.md", - "sha256": "318a12fb63ed4c788af86aa45ff1c95430f6f199bf012c1f966b073be469e7a9", - "size_bytes": 861, - "line_count": 21 - }, - { - "path": "docs/adr/0007-purpose-aware-privacy.md", - "sha256": "9ce6767604ee5787e0e2b4f051272cb7a2288be4dc8ba06e1b7bd3ffe54b0664", - "size_bytes": 944, - "line_count": 21 - }, - { - "path": "docs/adr/0008-ai-human-judgment.md", - "sha256": "1d2d14e8b6b0a03a18180a6e1a7efe9b2212afda74bd250c1c8745e5f700706d", - "size_bytes": 950, - "line_count": 21 - }, - { - "path": "docs/adr/0009-postgresql-system-of-record.md", - "sha256": "9ca96bc56d1658c933f89e3fe34b24cf0707e1b2e4862bc4929c8f4889b36bf7", - "size_bytes": 862, - "line_count": 21 - }, - { - "path": "docs/adr/0010-rust-compute-boundary.md", - "sha256": "b9e7d8f0da93a8c5f8dec5892d097c2eaab7eb4057b1a0f7a510ff22f29a5ccf", - "size_bytes": 979, - "line_count": 21 - }, - { - "path": "docs/adr/0011-contract-versioning.md", - "sha256": "76381bc76cfd59fd2a4bbd8831c217f1e6ca2625079d5c59b90d09fadc5f8afb", - "size_bytes": 877, - "line_count": 21 - }, - { - "path": "docs/adr/0012-quality-release-gates.md", - "sha256": "7083f64c1d394ad57cb8a1f19a9728b39dc032f59c6c159dabf2603751625144", - "size_bytes": 945, - "line_count": 21 - }, - { - "path": "docs/adr/0013-brand-and-license.md", - "sha256": "e27ab7029b52981abab21aacb1ed5fec8e458e1ff40163c4ab504c5426544b86", - "size_bytes": 3160, - "line_count": 32 - }, - { - "path": "docs/adr/0014-ux-design-system.md", - "sha256": "3121dfd4944a529a526a1ff3809d5c83a35360136973672f01a5d262f9a3d50a", - "size_bytes": 977, - "line_count": 21 - }, - { - "path": "docs/adr/0015-retention-disposition.md", - "sha256": "2b6b3fc4e3ddad2564e7bd9819d4aa4f980e3befb12d947ede25987a041e654c", - "size_bytes": 915, - "line_count": 21 - }, - { - "path": "docs/adr/0016-cwl-ecosystem-boundaries.md", - "sha256": "fb59ab82e8a9c5e19702412e25e22318587fd155a4dd41b14de6497b1de8066d", - "size_bytes": 964, - "line_count": 21 - }, - { - "path": "docs/adr/README.md", - "sha256": "ebd75a0c60d4dd3bd13f3135b3c81732013d8ace8ccc263b9ca7703fa406f5aa", - "size_bytes": 1818, - "line_count": 22 - }, - { - "path": "docs/doctoring/REFERENCES.md", - "sha256": "3508c3d2c9a886cb1e6fa5ed90a380e22feac730dcde737c953b1e1e04d3d5fb", - "size_bytes": 4519, - "line_count": 59 - }, - { - "path": "docs/doctoring/RESEARCH_BASIS.md", - "sha256": "1ecf6adb21fc6cfbf355fb61256c93fb20028ae228b8c910d97a867d73f184a4", - "size_bytes": 2221, - "line_count": 29 - }, - { - "path": "docs/doctoring/STANDARD_TRACEABILITY.md", - "sha256": "38d44ddfab32c0a7bf2bb7935bded795dd0a84800427e5518d64ff6a261f2314", - "size_bytes": 2560, - "line_count": 22 - }, - { - "path": "docs/index.md", - "sha256": "d7641f7c026b0bba9c7c8539b68c729517aade17de6af3656c5bf2942fded9a3", - "size_bytes": 4611, - "line_count": 49 - }, - { - "path": "docs/product-technical-gap-baseline.md", - "sha256": "f2a2012b9f73eeaaa5d0052eb1328d56cedd23a937acb19850e76f515fa0dccd", - "size_bytes": 11455, - "line_count": 149 - }, - { - "path": "docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md", - "sha256": "d453a94d4b5d2650aff49619da9733d057c5df80b241fe6a43ee0d95db99ebed", - "size_bytes": 16116, - "line_count": 433 - }, - { - "path": "docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md", - "sha256": "45debe0ac12d4648d21c0a8fb53fb9b30b07188a6b8e3ce0c9e4e22ebc34d999", - "size_bytes": 4509, - "line_count": 67 - }, - { - "path": "schemas/asyncapi.yaml", - "sha256": "b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c", - "size_bytes": 3682, - "line_count": 126 - }, - { - "path": "schemas/events/opportunity-stage-changed-v1.schema.json", - "sha256": "03c3ac79ffe93f518255401c12cc809eda31b4b5623bdc81474f44dcc8bf28b8", - "size_bytes": 1486, - "line_count": 63 - }, - { - "path": "schemas/events/relationship-changed-v1.schema.json", - "sha256": "bfcb12a02e472b74a20152a5671f5ebf18d80389a8bbe466e289873645a4945f", - "size_bytes": 1545, - "line_count": 72 - }, - { - "path": "schemas/openapi.yaml", - "sha256": "0e31e63c4c3e2bd95d58c7a17b064f106ca807a1a83d086af01641c2cfecff3b", - "size_bytes": 13246, - "line_count": 504 - } - ] -} +{"schema_version":"1.0","product":"ELUNVERA","generated_at":"2026-09-02T11:30:00Z","algorithm":"SHA-256","self_excluded":true,"file_count":58,"files":[{"path":".coderabbit.yaml","sha256":"efe46b993fae145eeaa2b2fb2cf0c302000c6373e5246c8e54bf330d636f4e2b","size_bytes":112,"line_count":7},{"path":".cwl/data-management.yaml","sha256":"28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671","size_bytes":1727,"line_count":48},{"path":".github/pull_request_template.md","sha256":"d7584adf5eb9866449fc5f38dc490422bf23de31ae75e1bdb385265c68122d15","size_bytes":1064,"line_count":38},{"path":".github/workflows/document-contracts.yml","sha256":"75b538b91bb9af0aa170ed864027c338382b51cab1595b19346e8b709c25759c","size_bytes":9391,"line_count":200},{"path":"AGENTS.md","sha256":"6c97e76c8ec1da4d30b82a1759755bae11018c132ca0fd29d7dfc803b55006a1","size_bytes":4152,"line_count":84},{"path":"CHANGELOG.md","sha256":"0b2dd24cb362ec7ed0bf16cc72b583e97dafdbc648886356c116f6c9ecae7b90","size_bytes":3694,"line_count":42},{"path":"CLAUDE.md","sha256":"67f513ae368f851201f50b6f732f444a648b3a940ca261411edbbc4c9f1ab223","size_bytes":1684,"line_count":34},{"path":"CONTRIBUTING.md","sha256":"5aee2d583ac082626a59cca4a832715ab6c9ef0e406ae48c7976887c71a74127","size_bytes":1696,"line_count":43},{"path":"LICENSE","sha256":"b7fa79459ac09645fd5bed5363852ba8759fa6deeb972d02f09fb0dc50fef586","size_bytes":11290,"line_count":192},{"path":"README.md","sha256":"3c65f74b492dfe6ae8e06eedd23a5ffde397d06b751d10a29f464c0621b77b04","size_bytes":5471,"line_count":84},{"path":"SECURITY.md","sha256":"4bfbb000844294b22ff9882211ee0a57b38e637002847cfdde8818b9276851eb","size_bytes":1091,"line_count":32},{"path":"docs/API_CONTRACT.md","sha256":"82f5d44989a1d7000dd586dde95ad71e00f52aec05d053bacbebd5f22988cfb5","size_bytes":8811,"line_count":226},{"path":"docs/ARCHITECTURE.md","sha256":"f4e39936636d48ed0d4d1c21f02562860be1af19fe8eec2d75e1d9049c30861f","size_bytes":9402,"line_count":250},{"path":"docs/DATA_MODEL.md","sha256":"3bbfe050809c960406514ff3ad0d8a273dc84b80c377189fd23f2c80f40da10a","size_bytes":15101,"line_count":504},{"path":"docs/OPERABILITY.md","sha256":"1c725823885df063bb43d8d9e4d80258ed6b9ef5029bb97cdf5100f7ec7dc80d","size_bytes":7003,"line_count":151},{"path":"docs/PRD.md","sha256":"fa61eb2cfda4013ef6d2d083b1e2ea21a307f77768e689ea5eb8f24987a6c15f","size_bytes":23521,"line_count":369},{"path":"docs/PRIVACY.md","sha256":"0599406e743af7c561208da8ad505c704ea585cebeb941444d221584aad5e004","size_bytes":6899,"line_count":141},{"path":"docs/ROADMAP.md","sha256":"3e94efa42e1553428dd90c8bd6b298b114a1af8188faa0968f690b6dd4f9a486","size_bytes":3415,"line_count":84},{"path":"docs/SECURITY.md","sha256":"d10ae9757a7233b9ce73eaa038f75939d22da4709ac6db7ee16fe4b291bd64dd","size_bytes":8100,"line_count":174},{"path":"docs/STORYBOARD.md","sha256":"c9e2d38ca25e024a7599afeff711187be272cebc7c51a9ca603846bf33bda392","size_bytes":2775,"line_count":41},{"path":"docs/STORYBOOK_INVENTORY.md","sha256":"e210ed7072720bef3b825f226419ff25dd68ee412d5272f0e5d51234b8ea4fe1","size_bytes":2354,"line_count":99},{"path":"docs/TEST_STRATEGY.md","sha256":"b1240c75308ea22db6f4c7d2e2f7ac16d11497c5d551f3c994113d6ac67f6a17","size_bytes":9456,"line_count":178},{"path":"docs/THREAT_MODEL.md","sha256":"1dc10db1d5fb0a314e25cd78c9bb1ed90b40315dbb3a32d387c2b5758910100f","size_bytes":7043,"line_count":132},{"path":"docs/TRD.md","sha256":"fa1e830ba1eecf773ea265e3d2ae620af5ab15d00f8d9ea53d8f511322934c5a","size_bytes":17622,"line_count":359},{"path":"docs/UML.md","sha256":"882a33a38bda7494e370f4135b9a3d7c5d3cf054d47cc511f3813eb046916d0c","size_bytes":3165,"line_count":115},{"path":"docs/USER_STORIES.md","sha256":"cdc8e1a2b74d7821279dfe0f07dda2d25b9bae088a720b9a6fb19270af36208c","size_bytes":3184,"line_count":37},{"path":"docs/USE_CASES.md","sha256":"4df536423c1796793edd35c200b624e6ec1daa87adf6ace9748608f24c254022","size_bytes":4357,"line_count":69},{"path":"docs/UX_SPEC.md","sha256":"e57641260cbb7ca177c773478699e03dca06b4bce3e4f994f0476187881e2919","size_bytes":8021,"line_count":178},{"path":"docs/VALIDATION_REPORT.md","sha256":"71b913ecac5bea2f94d10933c959bff0c0ba28110ee3be087a8578db08391ab8","size_bytes":2895,"line_count":56},{"path":"docs/WIREFRAMES.md","sha256":"e989815acd882701ff2737036ae6f278b5a01c45081204c3c65c33c9dc0e4f01","size_bytes":4526,"line_count":81},{"path":"docs/adr/0001-product-boundary.md","sha256":"86f3513bdfa2c2c8766c6c2afdbec7b099778982e9246efe729b5d9f76da3e24","size_bytes":1151,"line_count":21},{"path":"docs/adr/0002-modular-monolith.md","sha256":"0415bc80db206f5581c758a83f09abe14bfa5e45e76fbc2b38b7bb958d2342bb","size_bytes":955,"line_count":21},{"path":"docs/adr/0003-keyverse-identity.md","sha256":"10fccb512eff2665cf0b43ef5bbef1cdf4501962e0ae353777f131a75552c309","size_bytes":865,"line_count":21},{"path":"docs/adr/0004-bitemporal-truth.md","sha256":"d7d85c1fefeed397e417653a46e1ddd2d9505740f9369d2f16769dac344d373c","size_bytes":875,"line_count":21},{"path":"docs/adr/0005-first-class-relationships.md","sha256":"1130b14f9f448d3aba40086cb1355683c0d5b4891368706c860b41e5467a5852","size_bytes":848,"line_count":21},{"path":"docs/adr/0006-provider-neutral-integrations.md","sha256":"318a12fb63ed4c788af86aa45ff1c95430f6f199bf012c1f966b073be469e7a9","size_bytes":861,"line_count":21},{"path":"docs/adr/0007-purpose-aware-privacy.md","sha256":"9ce6767604ee5787e0e2b4f051272cb7a2288be4dc8ba06e1b7bd3ffe54b0664","size_bytes":944,"line_count":21},{"path":"docs/adr/0008-ai-human-judgment.md","sha256":"1d2d14e8b6b0a03a18180a6e1a7efe9b2212afda74bd250c1c8745e5f700706d","size_bytes":950,"line_count":21},{"path":"docs/adr/0009-postgresql-system-of-record.md","sha256":"9ca96bc56d1658c933f89e3fe34b24cf0707e1b2e4862bc4929c8f4889b36bf7","size_bytes":862,"line_count":21},{"path":"docs/adr/0010-rust-compute-boundary.md","sha256":"b9e7d8f0da93a8c5f8dec5892d097c2eaab7eb4057b1a0f7a510ff22f29a5ccf","size_bytes":979,"line_count":21},{"path":"docs/adr/0011-contract-versioning.md","sha256":"76381bc76cfd59fd2a4bbd8831c217f1e6ca2625079d5c59b90d09fadc5f8afb","size_bytes":877,"line_count":21},{"path":"docs/adr/0012-quality-release-gates.md","sha256":"7083f64c1d394ad57cb8a1f19a9728b39dc032f59c6c159dabf2603751625144","size_bytes":945,"line_count":21},{"path":"docs/adr/0013-brand-and-license.md","sha256":"e27ab7029b52981abab21aacb1ed5fec8e458e1ff40163c4ab504c5426544b86","size_bytes":3160,"line_count":32},{"path":"docs/adr/0014-ux-design-system.md","sha256":"3121dfd4944a529a526a1ff3809d5c83a35360136973672f01a5d262f9a3d50a","size_bytes":977,"line_count":21},{"path":"docs/adr/0015-retention-disposition.md","sha256":"2b6b3fc4e3ddad2564e7bd9819d4aa4f980e3befb12d947ede25987a041e654c","size_bytes":915,"line_count":21},{"path":"docs/adr/0016-cwl-ecosystem-boundaries.md","sha256":"fb59ab82e8a9c5e19702412e25e22318587fd155a4dd41b14de6497b1de8066d","size_bytes":964,"line_count":21},{"path":"docs/adr/README.md","sha256":"ebd75a0c60d4dd3bd13f3135b3c81732013d8ace8ccc263b9ca7703fa406f5aa","size_bytes":1818,"line_count":22},{"path":"docs/doctoring/REFERENCES.md","sha256":"3508c3d2c9a886cb1e6fa5ed90a380e22feac730dcde737c953b1e1e04d3d5fb","size_bytes":4519,"line_count":59},{"path":"docs/doctoring/RESEARCH_BASIS.md","sha256":"1ecf6adb21fc6cfbf355fb61256c93fb20028ae228b8c910d97a867d73f184a4","size_bytes":2221,"line_count":29},{"path":"docs/doctoring/STANDARD_TRACEABILITY.md","sha256":"38d44ddfab32c0a7bf2bb7935bded795dd0a84800427e5518d64ff6a261f2314","size_bytes":2560,"line_count":22},{"path":"docs/index.md","sha256":"d7641f7c026b0bba9c7c8539b68c729517aade17de6af3656c5bf2942fded9a3","size_bytes":4611,"line_count":49},{"path":"docs/product-technical-gap-baseline.md","sha256":"34fe353d5903e29ca7c49a0e3acbc9b73637c3962c072868242adf6791ca2177","size_bytes":15753,"line_count":190},{"path":"docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md","sha256":"d453a94d4b5d2650aff49619da9733d057c5df80b241fe6a43ee0d95db99ebed","size_bytes":16116,"line_count":433},{"path":"docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md","sha256":"45debe0ac12d4648d21c0a8fb53fb9b30b07188a6b8e3ce0c9e4e22ebc34d999","size_bytes":4509,"line_count":67},{"path":"schemas/asyncapi.yaml","sha256":"b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c","size_bytes":3682,"line_count":126},{"path":"schemas/events/opportunity-stage-changed-v1.schema.json","sha256":"03c3ac79ffe93f518255401c12cc809eda31b4b5623bdc81474f44dcc8bf28b8","size_bytes":1486,"line_count":63},{"path":"schemas/events/relationship-changed-v1.schema.json","sha256":"bfcb12a02e472b74a20152a5671f5ebf18d80389a8bbe466e289873645a4945f","size_bytes":1545,"line_count":72},{"path":"schemas/openapi.yaml","sha256":"0e31e63c4c3e2bd95d58c7a17b064f106ca807a1a83d086af01641c2cfecff3b","size_bytes":13246,"line_count":504}]} From 7a4928ad2157a41fabeb34dc11359d184fdf0d95 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 21:07:26 +0900 Subject: [PATCH 82/87] ci(actions): restamp current head after startup failure From e964db01a38d554b931f065fe8eee0d08060710b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 4 Sep 2026 21:36:37 +0900 Subject: [PATCH 83/87] chore: refresh head after Actions startup failure From 223228fd5ad8e37f6c5448ac6537dee9ae1c8598 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Sat, 5 Sep 2026 00:26:33 +0900 Subject: [PATCH 84/87] ci(actions): scope document checks by pull request --- .github/workflows/document-contracts.yml | 2 +- manifest.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/document-contracts.yml b/.github/workflows/document-contracts.yml index 3d13ca5..717b205 100644 --- a/.github/workflows/document-contracts.yml +++ b/.github/workflows/document-contracts.yml @@ -14,7 +14,7 @@ permissions: contents: read concurrency: - group: document-contracts-${{ github.event.pull_request.number || github.ref }} + group: document-contracts-${{ github.repository }}-${{ github.event.pull_request.number || github.run_id }} cancel-in-progress: true jobs: diff --git a/manifest.json b/manifest.json index 635add5..61ee88d 100644 --- a/manifest.json +++ b/manifest.json @@ -1 +1 @@ -{"schema_version":"1.0","product":"ELUNVERA","generated_at":"2026-09-02T11:30:00Z","algorithm":"SHA-256","self_excluded":true,"file_count":58,"files":[{"path":".coderabbit.yaml","sha256":"efe46b993fae145eeaa2b2fb2cf0c302000c6373e5246c8e54bf330d636f4e2b","size_bytes":112,"line_count":7},{"path":".cwl/data-management.yaml","sha256":"28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671","size_bytes":1727,"line_count":48},{"path":".github/pull_request_template.md","sha256":"d7584adf5eb9866449fc5f38dc490422bf23de31ae75e1bdb385265c68122d15","size_bytes":1064,"line_count":38},{"path":".github/workflows/document-contracts.yml","sha256":"75b538b91bb9af0aa170ed864027c338382b51cab1595b19346e8b709c25759c","size_bytes":9391,"line_count":200},{"path":"AGENTS.md","sha256":"6c97e76c8ec1da4d30b82a1759755bae11018c132ca0fd29d7dfc803b55006a1","size_bytes":4152,"line_count":84},{"path":"CHANGELOG.md","sha256":"0b2dd24cb362ec7ed0bf16cc72b583e97dafdbc648886356c116f6c9ecae7b90","size_bytes":3694,"line_count":42},{"path":"CLAUDE.md","sha256":"67f513ae368f851201f50b6f732f444a648b3a940ca261411edbbc4c9f1ab223","size_bytes":1684,"line_count":34},{"path":"CONTRIBUTING.md","sha256":"5aee2d583ac082626a59cca4a832715ab6c9ef0e406ae48c7976887c71a74127","size_bytes":1696,"line_count":43},{"path":"LICENSE","sha256":"b7fa79459ac09645fd5bed5363852ba8759fa6deeb972d02f09fb0dc50fef586","size_bytes":11290,"line_count":192},{"path":"README.md","sha256":"3c65f74b492dfe6ae8e06eedd23a5ffde397d06b751d10a29f464c0621b77b04","size_bytes":5471,"line_count":84},{"path":"SECURITY.md","sha256":"4bfbb000844294b22ff9882211ee0a57b38e637002847cfdde8818b9276851eb","size_bytes":1091,"line_count":32},{"path":"docs/API_CONTRACT.md","sha256":"82f5d44989a1d7000dd586dde95ad71e00f52aec05d053bacbebd5f22988cfb5","size_bytes":8811,"line_count":226},{"path":"docs/ARCHITECTURE.md","sha256":"f4e39936636d48ed0d4d1c21f02562860be1af19fe8eec2d75e1d9049c30861f","size_bytes":9402,"line_count":250},{"path":"docs/DATA_MODEL.md","sha256":"3bbfe050809c960406514ff3ad0d8a273dc84b80c377189fd23f2c80f40da10a","size_bytes":15101,"line_count":504},{"path":"docs/OPERABILITY.md","sha256":"1c725823885df063bb43d8d9e4d80258ed6b9ef5029bb97cdf5100f7ec7dc80d","size_bytes":7003,"line_count":151},{"path":"docs/PRD.md","sha256":"fa61eb2cfda4013ef6d2d083b1e2ea21a307f77768e689ea5eb8f24987a6c15f","size_bytes":23521,"line_count":369},{"path":"docs/PRIVACY.md","sha256":"0599406e743af7c561208da8ad505c704ea585cebeb941444d221584aad5e004","size_bytes":6899,"line_count":141},{"path":"docs/ROADMAP.md","sha256":"3e94efa42e1553428dd90c8bd6b298b114a1af8188faa0968f690b6dd4f9a486","size_bytes":3415,"line_count":84},{"path":"docs/SECURITY.md","sha256":"d10ae9757a7233b9ce73eaa038f75939d22da4709ac6db7ee16fe4b291bd64dd","size_bytes":8100,"line_count":174},{"path":"docs/STORYBOARD.md","sha256":"c9e2d38ca25e024a7599afeff711187be272cebc7c51a9ca603846bf33bda392","size_bytes":2775,"line_count":41},{"path":"docs/STORYBOOK_INVENTORY.md","sha256":"e210ed7072720bef3b825f226419ff25dd68ee412d5272f0e5d51234b8ea4fe1","size_bytes":2354,"line_count":99},{"path":"docs/TEST_STRATEGY.md","sha256":"b1240c75308ea22db6f4c7d2e2f7ac16d11497c5d551f3c994113d6ac67f6a17","size_bytes":9456,"line_count":178},{"path":"docs/THREAT_MODEL.md","sha256":"1dc10db1d5fb0a314e25cd78c9bb1ed90b40315dbb3a32d387c2b5758910100f","size_bytes":7043,"line_count":132},{"path":"docs/TRD.md","sha256":"fa1e830ba1eecf773ea265e3d2ae620af5ab15d00f8d9ea53d8f511322934c5a","size_bytes":17622,"line_count":359},{"path":"docs/UML.md","sha256":"882a33a38bda7494e370f4135b9a3d7c5d3cf054d47cc511f3813eb046916d0c","size_bytes":3165,"line_count":115},{"path":"docs/USER_STORIES.md","sha256":"cdc8e1a2b74d7821279dfe0f07dda2d25b9bae088a720b9a6fb19270af36208c","size_bytes":3184,"line_count":37},{"path":"docs/USE_CASES.md","sha256":"4df536423c1796793edd35c200b624e6ec1daa87adf6ace9748608f24c254022","size_bytes":4357,"line_count":69},{"path":"docs/UX_SPEC.md","sha256":"e57641260cbb7ca177c773478699e03dca06b4bce3e4f994f0476187881e2919","size_bytes":8021,"line_count":178},{"path":"docs/VALIDATION_REPORT.md","sha256":"71b913ecac5bea2f94d10933c959bff0c0ba28110ee3be087a8578db08391ab8","size_bytes":2895,"line_count":56},{"path":"docs/WIREFRAMES.md","sha256":"e989815acd882701ff2737036ae6f278b5a01c45081204c3c65c33c9dc0e4f01","size_bytes":4526,"line_count":81},{"path":"docs/adr/0001-product-boundary.md","sha256":"86f3513bdfa2c2c8766c6c2afdbec7b099778982e9246efe729b5d9f76da3e24","size_bytes":1151,"line_count":21},{"path":"docs/adr/0002-modular-monolith.md","sha256":"0415bc80db206f5581c758a83f09abe14bfa5e45e76fbc2b38b7bb958d2342bb","size_bytes":955,"line_count":21},{"path":"docs/adr/0003-keyverse-identity.md","sha256":"10fccb512eff2665cf0b43ef5bbef1cdf4501962e0ae353777f131a75552c309","size_bytes":865,"line_count":21},{"path":"docs/adr/0004-bitemporal-truth.md","sha256":"d7d85c1fefeed397e417653a46e1ddd2d9505740f9369d2f16769dac344d373c","size_bytes":875,"line_count":21},{"path":"docs/adr/0005-first-class-relationships.md","sha256":"1130b14f9f448d3aba40086cb1355683c0d5b4891368706c860b41e5467a5852","size_bytes":848,"line_count":21},{"path":"docs/adr/0006-provider-neutral-integrations.md","sha256":"318a12fb63ed4c788af86aa45ff1c95430f6f199bf012c1f966b073be469e7a9","size_bytes":861,"line_count":21},{"path":"docs/adr/0007-purpose-aware-privacy.md","sha256":"9ce6767604ee5787e0e2b4f051272cb7a2288be4dc8ba06e1b7bd3ffe54b0664","size_bytes":944,"line_count":21},{"path":"docs/adr/0008-ai-human-judgment.md","sha256":"1d2d14e8b6b0a03a18180a6e1a7efe9b2212afda74bd250c1c8745e5f700706d","size_bytes":950,"line_count":21},{"path":"docs/adr/0009-postgresql-system-of-record.md","sha256":"9ca96bc56d1658c933f89e3fe34b24cf0707e1b2e4862bc4929c8f4889b36bf7","size_bytes":862,"line_count":21},{"path":"docs/adr/0010-rust-compute-boundary.md","sha256":"b9e7d8f0da93a8c5f8dec5892d097c2eaab7eb4057b1a0f7a510ff22f29a5ccf","size_bytes":979,"line_count":21},{"path":"docs/adr/0011-contract-versioning.md","sha256":"76381bc76cfd59fd2a4bbd8831c217f1e6ca2625079d5c59b90d09fadc5f8afb","size_bytes":877,"line_count":21},{"path":"docs/adr/0012-quality-release-gates.md","sha256":"7083f64c1d394ad57cb8a1f19a9728b39dc032f59c6c159dabf2603751625144","size_bytes":945,"line_count":21},{"path":"docs/adr/0013-brand-and-license.md","sha256":"e27ab7029b52981abab21aacb1ed5fec8e458e1ff40163c4ab504c5426544b86","size_bytes":3160,"line_count":32},{"path":"docs/adr/0014-ux-design-system.md","sha256":"3121dfd4944a529a526a1ff3809d5c83a35360136973672f01a5d262f9a3d50a","size_bytes":977,"line_count":21},{"path":"docs/adr/0015-retention-disposition.md","sha256":"2b6b3fc4e3ddad2564e7bd9819d4aa4f980e3befb12d947ede25987a041e654c","size_bytes":915,"line_count":21},{"path":"docs/adr/0016-cwl-ecosystem-boundaries.md","sha256":"fb59ab82e8a9c5e19702412e25e22318587fd155a4dd41b14de6497b1de8066d","size_bytes":964,"line_count":21},{"path":"docs/adr/README.md","sha256":"ebd75a0c60d4dd3bd13f3135b3c81732013d8ace8ccc263b9ca7703fa406f5aa","size_bytes":1818,"line_count":22},{"path":"docs/doctoring/REFERENCES.md","sha256":"3508c3d2c9a886cb1e6fa5ed90a380e22feac730dcde737c953b1e1e04d3d5fb","size_bytes":4519,"line_count":59},{"path":"docs/doctoring/RESEARCH_BASIS.md","sha256":"1ecf6adb21fc6cfbf355fb61256c93fb20028ae228b8c910d97a867d73f184a4","size_bytes":2221,"line_count":29},{"path":"docs/doctoring/STANDARD_TRACEABILITY.md","sha256":"38d44ddfab32c0a7bf2bb7935bded795dd0a84800427e5518d64ff6a261f2314","size_bytes":2560,"line_count":22},{"path":"docs/index.md","sha256":"d7641f7c026b0bba9c7c8539b68c729517aade17de6af3656c5bf2942fded9a3","size_bytes":4611,"line_count":49},{"path":"docs/product-technical-gap-baseline.md","sha256":"34fe353d5903e29ca7c49a0e3acbc9b73637c3962c072868242adf6791ca2177","size_bytes":15753,"line_count":190},{"path":"docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md","sha256":"d453a94d4b5d2650aff49619da9733d057c5df80b241fe6a43ee0d95db99ebed","size_bytes":16116,"line_count":433},{"path":"docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md","sha256":"45debe0ac12d4648d21c0a8fb53fb9b30b07188a6b8e3ce0c9e4e22ebc34d999","size_bytes":4509,"line_count":67},{"path":"schemas/asyncapi.yaml","sha256":"b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c","size_bytes":3682,"line_count":126},{"path":"schemas/events/opportunity-stage-changed-v1.schema.json","sha256":"03c3ac79ffe93f518255401c12cc809eda31b4b5623bdc81474f44dcc8bf28b8","size_bytes":1486,"line_count":63},{"path":"schemas/events/relationship-changed-v1.schema.json","sha256":"bfcb12a02e472b74a20152a5671f5ebf18d80389a8bbe466e289873645a4945f","size_bytes":1545,"line_count":72},{"path":"schemas/openapi.yaml","sha256":"0e31e63c4c3e2bd95d58c7a17b064f106ca807a1a83d086af01641c2cfecff3b","size_bytes":13246,"line_count":504}]} +{"schema_version":"1.0","product":"ELUNVERA","generated_at":"2026-09-02T11:30:00Z","algorithm":"SHA-256","self_excluded":true,"file_count":58,"files":[{"path":".coderabbit.yaml","sha256":"efe46b993fae145eeaa2b2fb2cf0c302000c6373e5246c8e54bf330d636f4e2b","size_bytes":112,"line_count":7},{"path":".cwl/data-management.yaml","sha256":"28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671","size_bytes":1727,"line_count":48},{"path":".github/pull_request_template.md","sha256":"d7584adf5eb9866449fc5f38dc490422bf23de31ae75e1bdb385265c68122d15","size_bytes":1064,"line_count":38},{"path":".github/workflows/document-contracts.yml","sha256":"c93f8017c9ff5c0958f8753da9af43230d1635883570e91ab0c15d8968a8ea91","size_bytes":9419,"line_count":200},{"path":"AGENTS.md","sha256":"6c97e76c8ec1da4d30b82a1759755bae11018c132ca0fd29d7dfc803b55006a1","size_bytes":4152,"line_count":84},{"path":"CHANGELOG.md","sha256":"0b2dd24cb362ec7ed0bf16cc72b583e97dafdbc648886356c116f6c9ecae7b90","size_bytes":3694,"line_count":42},{"path":"CLAUDE.md","sha256":"67f513ae368f851201f50b6f732f444a648b3a940ca261411edbbc4c9f1ab223","size_bytes":1684,"line_count":34},{"path":"CONTRIBUTING.md","sha256":"5aee2d583ac082626a59cca4a832715ab6c9ef0e406ae48c7976887c71a74127","size_bytes":1696,"line_count":43},{"path":"LICENSE","sha256":"b7fa79459ac09645fd5bed5363852ba8759fa6deeb972d02f09fb0dc50fef586","size_bytes":11290,"line_count":192},{"path":"README.md","sha256":"3c65f74b492dfe6ae8e06eedd23a5ffde397d06b751d10a29f464c0621b77b04","size_bytes":5471,"line_count":84},{"path":"SECURITY.md","sha256":"4bfbb000844294b22ff9882211ee0a57b38e637002847cfdde8818b9276851eb","size_bytes":1091,"line_count":32},{"path":"docs/API_CONTRACT.md","sha256":"82f5d44989a1d7000dd586dde95ad71e00f52aec05d053bacbebd5f22988cfb5","size_bytes":8811,"line_count":226},{"path":"docs/ARCHITECTURE.md","sha256":"f4e39936636d48ed0d4d1c21f02562860be1af19fe8eec2d75e1d9049c30861f","size_bytes":9402,"line_count":250},{"path":"docs/DATA_MODEL.md","sha256":"3bbfe050809c960406514ff3ad0d8a273dc84b80c377189fd23f2c80f40da10a","size_bytes":15101,"line_count":504},{"path":"docs/OPERABILITY.md","sha256":"1c725823885df063bb43d8d9e4d80258ed6b9ef5029bb97cdf5100f7ec7dc80d","size_bytes":7003,"line_count":151},{"path":"docs/PRD.md","sha256":"fa61eb2cfda4013ef6d2d083b1e2ea21a307f77768e689ea5eb8f24987a6c15f","size_bytes":23521,"line_count":369},{"path":"docs/PRIVACY.md","sha256":"0599406e743af7c561208da8ad505c704ea585cebeb941444d221584aad5e004","size_bytes":6899,"line_count":141},{"path":"docs/ROADMAP.md","sha256":"3e94efa42e1553428dd90c8bd6b298b114a1af8188faa0968f690b6dd4f9a486","size_bytes":3415,"line_count":84},{"path":"docs/SECURITY.md","sha256":"d10ae9757a7233b9ce73eaa038f75939d22da4709ac6db7ee16fe4b291bd64dd","size_bytes":8100,"line_count":174},{"path":"docs/STORYBOARD.md","sha256":"c9e2d38ca25e024a7599afeff711187be272cebc7c51a9ca603846bf33bda392","size_bytes":2775,"line_count":41},{"path":"docs/STORYBOOK_INVENTORY.md","sha256":"e210ed7072720bef3b825f226419ff25dd68ee412d5272f0e5d51234b8ea4fe1","size_bytes":2354,"line_count":99},{"path":"docs/TEST_STRATEGY.md","sha256":"b1240c75308ea22db6f4c7d2e2f7ac16d11497c5d551f3c994113d6ac67f6a17","size_bytes":9456,"line_count":178},{"path":"docs/THREAT_MODEL.md","sha256":"1dc10db1d5fb0a314e25cd78c9bb1ed90b40315dbb3a32d387c2b5758910100f","size_bytes":7043,"line_count":132},{"path":"docs/TRD.md","sha256":"fa1e830ba1eecf773ea265e3d2ae620af5ab15d00f8d9ea53d8f511322934c5a","size_bytes":17622,"line_count":359},{"path":"docs/UML.md","sha256":"882a33a38bda7494e370f4135b9a3d7c5d3cf054d47cc511f3813eb046916d0c","size_bytes":3165,"line_count":115},{"path":"docs/USER_STORIES.md","sha256":"cdc8e1a2b74d7821279dfe0f07dda2d25b9bae088a720b9a6fb19270af36208c","size_bytes":3184,"line_count":37},{"path":"docs/USE_CASES.md","sha256":"4df536423c1796793edd35c200b624e6ec1daa87adf6ace9748608f24c254022","size_bytes":4357,"line_count":69},{"path":"docs/UX_SPEC.md","sha256":"e57641260cbb7ca177c773478699e03dca06b4bce3e4f994f0476187881e2919","size_bytes":8021,"line_count":178},{"path":"docs/VALIDATION_REPORT.md","sha256":"71b913ecac5bea2f94d10933c959bff0c0ba28110ee3be087a8578db08391ab8","size_bytes":2895,"line_count":56},{"path":"docs/WIREFRAMES.md","sha256":"e989815acd882701ff2737036ae6f278b5a01c45081204c3c65c33c9dc0e4f01","size_bytes":4526,"line_count":81},{"path":"docs/adr/0001-product-boundary.md","sha256":"86f3513bdfa2c2c8766c6c2afdbec7b099778982e9246efe729b5d9f76da3e24","size_bytes":1151,"line_count":21},{"path":"docs/adr/0002-modular-monolith.md","sha256":"0415bc80db206f5581c758a83f09abe14bfa5e45e76fbc2b38b7bb958d2342bb","size_bytes":955,"line_count":21},{"path":"docs/adr/0003-keyverse-identity.md","sha256":"10fccb512eff2665cf0b43ef5bbef1cdf4501962e0ae353777f131a75552c309","size_bytes":865,"line_count":21},{"path":"docs/adr/0004-bitemporal-truth.md","sha256":"d7d85c1fefeed397e417653a46e1ddd2d9505740f9369d2f16769dac344d373c","size_bytes":875,"line_count":21},{"path":"docs/adr/0005-first-class-relationships.md","sha256":"1130b14f9f448d3aba40086cb1355683c0d5b4891368706c860b41e5467a5852","size_bytes":848,"line_count":21},{"path":"docs/adr/0006-provider-neutral-integrations.md","sha256":"318a12fb63ed4c788af86aa45ff1c95430f6f199bf012c1f966b073be469e7a9","size_bytes":861,"line_count":21},{"path":"docs/adr/0007-purpose-aware-privacy.md","sha256":"9ce6767604ee5787e0e2b4f051272cb7a2288be4dc8ba06e1b7bd3ffe54b0664","size_bytes":944,"line_count":21},{"path":"docs/adr/0008-ai-human-judgment.md","sha256":"1d2d14e8b6b0a03a18180a6e1a7efe9b2212afda74bd250c1c8745e5f700706d","size_bytes":950,"line_count":21},{"path":"docs/adr/0009-postgresql-system-of-record.md","sha256":"9ca96bc56d1658c933f89e3fe34b24cf0707e1b2e4862bc4929c8f4889b36bf7","size_bytes":862,"line_count":21},{"path":"docs/adr/0010-rust-compute-boundary.md","sha256":"b9e7d8f0da93a8c5f8dec5892d097c2eaab7eb4057b1a0f7a510ff22f29a5ccf","size_bytes":979,"line_count":21},{"path":"docs/adr/0011-contract-versioning.md","sha256":"76381bc76cfd59fd2a4bbd8831c217f1e6ca2625079d5c59b90d09fadc5f8afb","size_bytes":877,"line_count":21},{"path":"docs/adr/0012-quality-release-gates.md","sha256":"7083f64c1d394ad57cb8a1f19a9728b39dc032f59c6c159dabf2603751625144","size_bytes":945,"line_count":21},{"path":"docs/adr/0013-brand-and-license.md","sha256":"e27ab7029b52981abab21aacb1ed5fec8e458e1ff40163c4ab504c5426544b86","size_bytes":3160,"line_count":32},{"path":"docs/adr/0014-ux-design-system.md","sha256":"3121dfd4944a529a526a1ff3809d5c83a35360136973672f01a5d262f9a3d50a","size_bytes":977,"line_count":21},{"path":"docs/adr/0015-retention-disposition.md","sha256":"2b6b3fc4e3ddad2564e7bd9819d4aa4f980e3befb12d947ede25987a041e654c","size_bytes":915,"line_count":21},{"path":"docs/adr/0016-cwl-ecosystem-boundaries.md","sha256":"fb59ab82e8a9c5e19702412e25e22318587fd155a4dd41b14de6497b1de8066d","size_bytes":964,"line_count":21},{"path":"docs/adr/README.md","sha256":"ebd75a0c60d4dd3bd13f3135b3c81732013d8ace8ccc263b9ca7703fa406f5aa","size_bytes":1818,"line_count":22},{"path":"docs/doctoring/REFERENCES.md","sha256":"3508c3d2c9a886cb1e6fa5ed90a380e22feac730dcde737c953b1e1e04d3d5fb","size_bytes":4519,"line_count":59},{"path":"docs/doctoring/RESEARCH_BASIS.md","sha256":"1ecf6adb21fc6cfbf355fb61256c93fb20028ae228b8c910d97a867d73f184a4","size_bytes":2221,"line_count":29},{"path":"docs/doctoring/STANDARD_TRACEABILITY.md","sha256":"38d44ddfab32c0a7bf2bb7935bded795dd0a84800427e5518d64ff6a261f2314","size_bytes":2560,"line_count":22},{"path":"docs/index.md","sha256":"d7641f7c026b0bba9c7c8539b68c729517aade17de6af3656c5bf2942fded9a3","size_bytes":4611,"line_count":49},{"path":"docs/product-technical-gap-baseline.md","sha256":"34fe353d5903e29ca7c49a0e3acbc9b73637c3962c072868242adf6791ca2177","size_bytes":15753,"line_count":190},{"path":"docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md","sha256":"d453a94d4b5d2650aff49619da9733d057c5df80b241fe6a43ee0d95db99ebed","size_bytes":16116,"line_count":433},{"path":"docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md","sha256":"45debe0ac12d4648d21c0a8fb53fb9b30b07188a6b8e3ce0c9e4e22ebc34d999","size_bytes":4509,"line_count":67},{"path":"schemas/asyncapi.yaml","sha256":"b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c","size_bytes":3682,"line_count":126},{"path":"schemas/events/opportunity-stage-changed-v1.schema.json","sha256":"03c3ac79ffe93f518255401c12cc809eda31b4b5623bdc81474f44dcc8bf28b8","size_bytes":1486,"line_count":63},{"path":"schemas/events/relationship-changed-v1.schema.json","sha256":"bfcb12a02e472b74a20152a5671f5ebf18d80389a8bbe466e289873645a4945f","size_bytes":1545,"line_count":72},{"path":"schemas/openapi.yaml","sha256":"0e31e63c4c3e2bd95d58c7a17b064f106ca807a1a83d086af01641c2cfecff3b","size_bytes":13246,"line_count":504}]} From 4a12ecd78071a3c9c3cac048ec7cb9d8c3b7d67d Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 1 Oct 2026 05:29:23 +0900 Subject: [PATCH 85/87] ci: enforce tracked text hygiene --- .github/workflows/document-contracts.yml | 15 +++ CHANGELOG.md | 1 + docs/VALIDATION_REPORT.md | 4 +- docs/product-technical-gap-baseline.md | 154 ++++++++++++++++------- manifest.json | 2 +- 5 files changed, 126 insertions(+), 50 deletions(-) diff --git a/.github/workflows/document-contracts.yml b/.github/workflows/document-contracts.yml index 717b205..b176c3d 100644 --- a/.github/workflows/document-contracts.yml +++ b/.github/workflows/document-contracts.yml @@ -155,6 +155,21 @@ jobs: assert 'recorded_at' in schema['required'] assert schema['properties']['recorded_at']['format'] == 'date-time' + trailing_whitespace = [] + for path_text in subprocess.check_output( + ['git', 'ls-files'], text=True + ).splitlines(): + payload = Path(path_text).read_bytes() + if b'\0' in payload: + continue + for line_number, line in enumerate(payload.splitlines(), 1): + if line.endswith((b' ', b'\t')): + trailing_whitespace.append(f'{path_text}:{line_number}') + assert not trailing_whitespace, ( + 'tracked text contains trailing whitespace: ' + + ', '.join(trailing_whitespace) + ) + manifest = json.loads(Path('manifest.json').read_text(encoding='utf-8')) tracked = { path diff --git a/CHANGELOG.md b/CHANGELOG.md index df5af93..701c593 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The format follows Keep a Changelog principles, and versioning will begin when t ### Fixed +- Made the permanent document-contract gate reject trailing whitespace in committed tracked text and cleaned the affected product-technical gap baseline. - Aligned the narrative HTTP inventory with the authoritative OpenAPI P0 surface. - Added temporal read parameters and effective-lens response headers to the machine-readable HTTP contract. - Corrected AsyncAPI operations to publish ELUNVERA domain events and required classification/schema metadata. diff --git a/docs/VALIDATION_REPORT.md b/docs/VALIDATION_REPORT.md index 7dd22bc..2f87704 100644 --- a/docs/VALIDATION_REPORT.md +++ b/docs/VALIDATION_REPORT.md @@ -1,6 +1,6 @@ # ELUNVERA Documentation Baseline Validation Report -- **Validation date:** 2026-09-02 +- **Validation date:** 2026-10-01 - **Scope:** Documentation, contracts, schemas, local links, source licensing, and artifact integrity - **Runtime claim:** None @@ -25,6 +25,7 @@ | Obvious database two-word `snake_case` declaration check | Pass | | Apache-2.0 repository source-license boundary | Pass | | Manifest SHA-256 verification | Pass after final manifest resealing | +| Tracked non-binary text trailing-whitespace scan | Pass | ## Inventory @@ -44,6 +45,7 @@ OpenAPI/AsyncAPI structural and cross-contract coherence checks Markdown relative-link and fence checks Placeholder and naming scans SHA-256 manifest generation and verification +Tracked non-binary text trailing-whitespace validation Git diff and branch-history inspection ``` diff --git a/docs/product-technical-gap-baseline.md b/docs/product-technical-gap-baseline.md index 1ca6339..331013b 100644 --- a/docs/product-technical-gap-baseline.md +++ b/docs/product-technical-gap-baseline.md @@ -1,7 +1,7 @@ # ELUNVERA Product–Technical Gap Baseline -- **Baseline version:** 0.4 -- **Observed date:** 2026-09-02 +- **Baseline version:** 0.5 +- **Observed date:** 2026-10-01 - **Repository:** `ContextualWisdomLab/ELUNVERA` - **Target integration branch:** `main` - **Evidence scope:** live repository/PR state plus this Draft foundation's PRD, TRD, architecture, data model, API/event contracts, UX, test strategy, ADRs, and source-license proposal @@ -68,106 +68,164 @@ The aggregate boundary is the smallest transactionally consistent business objec ### G-001 Repository governance -**Owner:** ELUNVERA + organization control plane where causal. -**Current evidence:** `main` and `develop` exist at the same bootstrap revision; `main` is canonical protected integration authority. The Draft foundation targets `main`; document-contract CI validates canonical branch authority and now also fails closed on performance/i18n contract drift. -**Gap:** exact-head required workflow completion, current semantic review, release-policy evidence, and any repository-specific ownership controls not centrally supplied remain unproven. -**Action:** preserve protected `main`, exact-head checks, independent review, and central reusable workflows; never weaken a leaf gate to compensate for hosted-runner or workflow-materialization failure. +**Owner:** ELUNVERA + organization control plane where causal. + +**Current evidence:** `main` remains the canonical protected integration authority. The Draft foundation targets `main`; exact head `223228fd5ad8e37f6c5448ac6537dee9ae1c8598` had terminal GREEN document-contract, Security, and SAST runs, while CodeQL run `33889504891` was cancelled and qualifying approval remained absent when observed on 2026-10-01. Document-contract CI validates canonical branch authority and fails closed on performance/i18n contract drift. + +**Gap:** exact-head required workflow completion, current semantic review, release-policy evidence, and any repository-specific ownership controls not centrally supplied remain unproven. + +**Action:** preserve protected `main`, exact-head checks, independent review, and central reusable workflows; never weaken a leaf gate to compensate for hosted-runner or workflow-materialization failure. + **Exit evidence:** unchanged exact-head required checks plus ordinary protected integration. ### G-002 Executable Rust foundation -**Owner:** ELUNVERA. -**Gap:** protected foundation has no Cargo workspace or production code. -**Action:** after foundation integration, build the smallest Rust domain/API slice test-first. Reconcile stacked PR #1 rather than discarding its valid Relationship Activation delta. +**Owner:** ELUNVERA. + +**Gap:** protected foundation has no Cargo workspace or production code. + +**Action:** after foundation integration, build the smallest Rust domain/API slice test-first. Reconcile stacked PR #1 rather than discarding its valid Relationship Activation delta. + **Exit evidence:** Rust build/lint/unit/property/doc/coverage results on exact source. ### G-003 PostgreSQL lifecycle -**Owner:** ELUNVERA. -**Gap:** no migration, RLS, temporal constraint, pool, item-level UPSERT implementation, hot-lock evidence, backup, or restore. -**Action:** pin supported PostgreSQL 18.x, create 3NF multi-word persistence objects, RLS, temporal constraints, outbox, explicit item-level UPSERT/idempotency, contention tests, clean/upgrade rehearsal, encrypted backup, and restore validation. +**Owner:** ELUNVERA. + +**Gap:** no migration, RLS, temporal constraint, pool, item-level UPSERT implementation, hot-lock evidence, backup, or restore. + +**Action:** pin supported PostgreSQL 18.x, create 3NF multi-word persistence objects, RLS, temporal constraints, outbox, explicit item-level UPSERT/idempotency, contention tests, clean/upgrade rehearsal, encrypted backup, and restore validation. + **Exit evidence:** PostgreSQL integration, lock/contention, migration, backup, and restore artifacts. ### G-004 Keyverse integration -**Owner:** Keyverse for released identity contract; ELUNVERA for product-owned login/signup/recovery UI and ACL. -**Gap:** no OIDC/JWKS/SCIM implementation or product authentication forms. -**Action:** consume only immutable released Keyverse contracts; implement exact issuer/audience/token validation and immutable authorization context; keep CRM party identity distinct from authentication subject. +**Owner:** Keyverse for released identity contract; ELUNVERA for product-owned login/signup/recovery UI and ACL. + +**Gap:** no OIDC/JWKS/SCIM implementation or product authentication forms. + +**Action:** consume only immutable released Keyverse contracts; implement exact issuer/audience/token validation and immutable authorization context; keep CRM party identity distinct from authentication subject. + **Exit evidence:** negative token, tenant, recovery, CSS/action-edge, and integration tests. ### G-005 Account and relationship UX -**Owner:** ELUNVERA. -**Gap:** no Figma file, product-owned reusable component system, Storybook, production UI, screenshots, or accessibility evidence. -**Action:** create the three-band account experience in Figma, record file ID in ADR, implement design tokens/product-owned components and Storybook normal/loading/empty/error/permission/responsive/interaction states, then run full screenshot/E2E/AT audit. +**Owner:** ELUNVERA. + +**Gap:** no Figma file, product-owned reusable component system, Storybook, production UI, screenshots, or accessibility evidence. + +**Action:** create the three-band account experience in Figma, record file ID in ADR, implement design tokens/product-owned components and Storybook normal/loading/empty/error/permission/responsive/interaction states, then run full screenshot/E2E/AT audit. + **Exit evidence:** reviewed Figma, Storybook, screenshots, interaction tests, and WCAG evidence. ### G-006 Provider and CWL contracts -**Owner:** canonical supplier for reusable defects; ELUNVERA for consumer ACLs/adapters. -**Gap:** adapters and consumer contracts do not exist. -**Action:** consume only released immutable contracts. For an immature owner, use a port/ACL/feature flag/test double until owner RED→fix→GREEN→immutable release; never copy owner source, read owner DB, or bind to a temporary branch. +**Owner:** canonical supplier for reusable defects; ELUNVERA for consumer ACLs/adapters. + +**Gap:** adapters and consumer contracts do not exist. + +**Action:** consume only released immutable contracts. For an immature owner, use a port/ACL/feature flag/test double until owner RED→fix→GREEN→immutable release; never copy owner source, read owner DB, or bind to a temporary branch. + **Exit evidence:** supplier release plus consumer conformance, duplicate/reorder, outage, and reconciliation tests. ### G-007 Privacy operation -**Owner:** ELUNVERA. -**Gap:** purpose, rights, retention, hold, export, and disposition are documentation only. -**Action:** implement policy decision receipts and complete rights/disposition workflows before production PII; use least privilege, encryption, field selection, purpose limitation, and audit rather than destructive masking where masking breaks legitimate work. +**Owner:** ELUNVERA. + +**Gap:** purpose, rights, retention, hold, export, and disposition are documentation only. + +**Action:** implement policy decision receipts and complete rights/disposition workflows before production PII; use least privilege, encryption, field selection, purpose limitation, and audit rather than destructive masking where masking breaks legitimate work. + **Exit evidence:** jurisdiction-reviewed policy plus realistic rights and non-masking-protection tests. ### G-008 Security and supply chain -**Owner:** `.github` for reusable controls; ELUNVERA for thin callers/product evidence. -**Gap:** no executable-product CI artifact, dependency/SBOM/provenance/signature, penetration evidence, or production runtime exists. -**Action:** use released central workflows, exact pins, minimal permissions, fail-closed dependency/security gates, and signed release pipeline when runtime arrives. +**Owner:** `.github` for reusable controls; ELUNVERA for thin callers/product evidence. + +**Gap:** no executable-product CI artifact, dependency/SBOM/provenance/signature, penetration evidence, or production runtime exists. + +**Action:** use released central workflows, exact pins, minimal permissions, fail-closed dependency/security gates, and signed release pipeline when runtime arrives. + **Exit evidence:** current-head checks, SBOM/provenance, signatures, and tested release candidate. ### G-009 Operability -**Owner:** ELUNVERA. -**Gap:** no health endpoints, telemetry, SLO, alert, capacity, incident, compose deployment, or recovery runtime. -**Action:** implement liveness/startup/readiness, async cancellation, OTLP, low-cardinality metrics, queue/backpressure, Compose for Docker/Podman/Colima, measured hardware tuning, runbooks, and recovery rehearsal. Verify `close_connection` assumptions in any framework/adapter before relying on them. +**Owner:** ELUNVERA. + +**Gap:** no health endpoints, telemetry, SLO, alert, capacity, incident, compose deployment, or recovery runtime. + +**Action:** implement liveness/startup/readiness, async cancellation, OTLP, low-cardinality metrics, queue/backpressure, Compose for Docker/Podman/Colima, measured hardware tuning, runbooks, and recovery rehearsal. Verify `close_connection` assumptions in any framework/adapter before relying on them. + **Exit evidence:** SLO dashboard, realistic capacity run, and operational drill receipts. ### G-010 Model governance and measurement -**Owner:** ELUNVERA model domain plus released TEPP/fast-mlsirm/contextual-orchestrator contracts. -**Gap:** no model, dataset, benchmark, validity, fairness, or calibration evidence. -**Action:** release no score until outcome/population/sampling design/error target/failure denominator are defined; keep production numerical computation in Rust, model multilevel/multiple-membership/time structure where relevant, and prohibit heuristic weights. +**Owner:** ELUNVERA model domain plus released TEPP/fast-mlsirm/contextual-orchestrator contracts. + +**Gap:** no model, dataset, benchmark, validity, fairness, or calibration evidence. + +**Action:** release no score until outcome/population/sampling design/error target/failure denominator are defined; keep production numerical computation in Rust, model multilevel/multiple-membership/time structure where relevant, and prohibit heuristic weights. + **Exit evidence:** model card, true-parameter recovery/validation, calibration/error analysis, and monitoring. ### G-011 Commercial and legal readiness -**Owner:** ELUNVERA/product/legal. -**Current proposed slice:** Apache License 2.0 for ContextualWisdomLab-authored source/docs under Proposed ADR-0013. -**Gap:** no trademark evidence, terms, DPA, support policy, pricing, entitlement, billing integration, dependency/asset inventory, or sellable deployment. -**Action:** complete legal/commercial package only after protected foundation/runtime evidence. +**Owner:** ELUNVERA/product/legal. + +**Current proposed slice:** Apache License 2.0 for ContextualWisdomLab-authored source/docs under Proposed ADR-0013. + +**Gap:** no trademark evidence, terms, DPA, support policy, pricing, entitlement, billing integration, dependency/asset inventory, or sellable deployment. + +**Action:** complete legal/commercial package only after protected foundation/runtime evidence. + **Exit evidence:** protected-main license/ADR integration plus reviewed commercial package and exact distributable SBOM/license/attribution evidence. ### G-012 Product validation -**Owner:** ELUNVERA product. -**Gap:** no customer interviews, usability data, activation, retention, willingness-to-pay, or outcome study. -**Action:** validate account-preparation, opportunity-review, and complaint-recovery jobs with target users and measure time-to-context, evidence coverage, correction rate, workflow outcome, and willingness-to-pay. +**Owner:** ELUNVERA product. + +**Gap:** no customer interviews, usability data, activation, retention, willingness-to-pay, or outcome study. + +**Action:** validate account-preparation, opportunity-review, and complaint-recovery jobs with target users and measure time-to-context, evidence coverage, correction rate, workflow outcome, and willingness-to-pay. + **Exit evidence:** research protocol and anonymized findings. ### G-013 Every-page performance contract -**Owner:** ELUNVERA. -**Evidence:** PRD/TRD/Test Strategy now require realistic every-buyer-page k6 p95 ≤ 20 ms; the permanent document-contract workflow prevents regression to weaker page targets. -**Gap:** no runtime exists, so no latency claim is proven. -**Action:** when UI/runtime starts, measure full declared page denominator including DB/query/render/bundle/heap/DOM/hydration/main-thread/GC and cold/cache profile. Fix causal algorithm/query/I/O/render/runtime/Rust hot path; never shrink data, omit slow samples, or use unrealistic warmup. +**Owner:** ELUNVERA. + +**Evidence:** PRD/TRD/Test Strategy now require realistic every-buyer-page k6 p95 ≤ 20 ms; the permanent document-contract workflow prevents regression to weaker page targets. + +**Gap:** no runtime exists, so no latency claim is proven. + +**Action:** when UI/runtime starts, measure full declared page denominator including DB/query/render/bundle/heap/DOM/hydration/main-thread/GC and cold/cache profile. Fix causal algorithm/query/I/O/render/runtime/Rust hot path; never shrink data, omit slow samples, or use unrealistic warmup. + **Exit evidence:** exact-head k6 artifacts for every buyer-facing page at p95 ≤ 20 ms. ### G-014 Translation-resource authority and eight-locale delivery -**Owner:** ELUNVERA unless a separately released reusable CWL translation product later proves common ownership. -**Evidence:** PRD/TRD/UX/Test Strategy now specify `ko/en/ja/zh/vi/es/de/fr`, DB-backed versioned translation resources, screen-key-scoped server/native fetch/cache, review/approval/deploy/rollback, and separation from ontology labels. -**Gap:** no schema/API/admin UI/cache/locale assets or Figma/Storybook/E2E evidence exists. -**Action:** implement `translation_resource`, `translation_revision`, and `translation_text` in 3NF with immutable approved revisions, explicit draft item UPSERT, revision-aware cache invalidation, product-owned admin UI, and locale-specific interaction/screenshot tests. +**Owner:** ELUNVERA unless a separately released reusable CWL translation product later proves common ownership. + +**Evidence:** PRD/TRD/UX/Test Strategy now specify `ko/en/ja/zh/vi/es/de/fr`, DB-backed versioned translation resources, screen-key-scoped server/native fetch/cache, review/approval/deploy/rollback, and separation from ontology labels. + +**Gap:** no schema/API/admin UI/cache/locale assets or Figma/Storybook/E2E evidence exists. + +**Action:** implement `translation_resource`, `translation_revision`, and `translation_text` in 3NF with immutable approved revisions, explicit draft item UPSERT, revision-aware cache invalidation, product-owned admin UI, and locale-specific interaction/screenshot tests. + **Exit evidence:** migration/API/admin UI + eight-locale Storybook/E2E + rollback and cache-invalidation receipts. +### G-015 Tracked-text hygiene + +**Owner:** ELUNVERA. + +**Evidence:** the previous exact-head document-contract workflow was GREEN even though a full PR-range `git diff --check` reported trailing whitespace in this baseline. The workflow's checkout-time `git diff --check` inspected only an empty working-tree diff. + +**Gap:** formatting regressions in committed tracked text were not enforced by the permanent gate. + +**Action:** validate every tracked non-binary file for trailing spaces or tabs, clean the current tree, and keep the check in the permanent document-contract workflow. + +**Exit evidence:** the strengthened validator and full PR-range `git diff --check` both pass on the same exact head. + ## 5. Highest-leverage implementation order ```text diff --git a/manifest.json b/manifest.json index 61ee88d..f3ab623 100644 --- a/manifest.json +++ b/manifest.json @@ -1 +1 @@ -{"schema_version":"1.0","product":"ELUNVERA","generated_at":"2026-09-02T11:30:00Z","algorithm":"SHA-256","self_excluded":true,"file_count":58,"files":[{"path":".coderabbit.yaml","sha256":"efe46b993fae145eeaa2b2fb2cf0c302000c6373e5246c8e54bf330d636f4e2b","size_bytes":112,"line_count":7},{"path":".cwl/data-management.yaml","sha256":"28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671","size_bytes":1727,"line_count":48},{"path":".github/pull_request_template.md","sha256":"d7584adf5eb9866449fc5f38dc490422bf23de31ae75e1bdb385265c68122d15","size_bytes":1064,"line_count":38},{"path":".github/workflows/document-contracts.yml","sha256":"c93f8017c9ff5c0958f8753da9af43230d1635883570e91ab0c15d8968a8ea91","size_bytes":9419,"line_count":200},{"path":"AGENTS.md","sha256":"6c97e76c8ec1da4d30b82a1759755bae11018c132ca0fd29d7dfc803b55006a1","size_bytes":4152,"line_count":84},{"path":"CHANGELOG.md","sha256":"0b2dd24cb362ec7ed0bf16cc72b583e97dafdbc648886356c116f6c9ecae7b90","size_bytes":3694,"line_count":42},{"path":"CLAUDE.md","sha256":"67f513ae368f851201f50b6f732f444a648b3a940ca261411edbbc4c9f1ab223","size_bytes":1684,"line_count":34},{"path":"CONTRIBUTING.md","sha256":"5aee2d583ac082626a59cca4a832715ab6c9ef0e406ae48c7976887c71a74127","size_bytes":1696,"line_count":43},{"path":"LICENSE","sha256":"b7fa79459ac09645fd5bed5363852ba8759fa6deeb972d02f09fb0dc50fef586","size_bytes":11290,"line_count":192},{"path":"README.md","sha256":"3c65f74b492dfe6ae8e06eedd23a5ffde397d06b751d10a29f464c0621b77b04","size_bytes":5471,"line_count":84},{"path":"SECURITY.md","sha256":"4bfbb000844294b22ff9882211ee0a57b38e637002847cfdde8818b9276851eb","size_bytes":1091,"line_count":32},{"path":"docs/API_CONTRACT.md","sha256":"82f5d44989a1d7000dd586dde95ad71e00f52aec05d053bacbebd5f22988cfb5","size_bytes":8811,"line_count":226},{"path":"docs/ARCHITECTURE.md","sha256":"f4e39936636d48ed0d4d1c21f02562860be1af19fe8eec2d75e1d9049c30861f","size_bytes":9402,"line_count":250},{"path":"docs/DATA_MODEL.md","sha256":"3bbfe050809c960406514ff3ad0d8a273dc84b80c377189fd23f2c80f40da10a","size_bytes":15101,"line_count":504},{"path":"docs/OPERABILITY.md","sha256":"1c725823885df063bb43d8d9e4d80258ed6b9ef5029bb97cdf5100f7ec7dc80d","size_bytes":7003,"line_count":151},{"path":"docs/PRD.md","sha256":"fa61eb2cfda4013ef6d2d083b1e2ea21a307f77768e689ea5eb8f24987a6c15f","size_bytes":23521,"line_count":369},{"path":"docs/PRIVACY.md","sha256":"0599406e743af7c561208da8ad505c704ea585cebeb941444d221584aad5e004","size_bytes":6899,"line_count":141},{"path":"docs/ROADMAP.md","sha256":"3e94efa42e1553428dd90c8bd6b298b114a1af8188faa0968f690b6dd4f9a486","size_bytes":3415,"line_count":84},{"path":"docs/SECURITY.md","sha256":"d10ae9757a7233b9ce73eaa038f75939d22da4709ac6db7ee16fe4b291bd64dd","size_bytes":8100,"line_count":174},{"path":"docs/STORYBOARD.md","sha256":"c9e2d38ca25e024a7599afeff711187be272cebc7c51a9ca603846bf33bda392","size_bytes":2775,"line_count":41},{"path":"docs/STORYBOOK_INVENTORY.md","sha256":"e210ed7072720bef3b825f226419ff25dd68ee412d5272f0e5d51234b8ea4fe1","size_bytes":2354,"line_count":99},{"path":"docs/TEST_STRATEGY.md","sha256":"b1240c75308ea22db6f4c7d2e2f7ac16d11497c5d551f3c994113d6ac67f6a17","size_bytes":9456,"line_count":178},{"path":"docs/THREAT_MODEL.md","sha256":"1dc10db1d5fb0a314e25cd78c9bb1ed90b40315dbb3a32d387c2b5758910100f","size_bytes":7043,"line_count":132},{"path":"docs/TRD.md","sha256":"fa1e830ba1eecf773ea265e3d2ae620af5ab15d00f8d9ea53d8f511322934c5a","size_bytes":17622,"line_count":359},{"path":"docs/UML.md","sha256":"882a33a38bda7494e370f4135b9a3d7c5d3cf054d47cc511f3813eb046916d0c","size_bytes":3165,"line_count":115},{"path":"docs/USER_STORIES.md","sha256":"cdc8e1a2b74d7821279dfe0f07dda2d25b9bae088a720b9a6fb19270af36208c","size_bytes":3184,"line_count":37},{"path":"docs/USE_CASES.md","sha256":"4df536423c1796793edd35c200b624e6ec1daa87adf6ace9748608f24c254022","size_bytes":4357,"line_count":69},{"path":"docs/UX_SPEC.md","sha256":"e57641260cbb7ca177c773478699e03dca06b4bce3e4f994f0476187881e2919","size_bytes":8021,"line_count":178},{"path":"docs/VALIDATION_REPORT.md","sha256":"71b913ecac5bea2f94d10933c959bff0c0ba28110ee3be087a8578db08391ab8","size_bytes":2895,"line_count":56},{"path":"docs/WIREFRAMES.md","sha256":"e989815acd882701ff2737036ae6f278b5a01c45081204c3c65c33c9dc0e4f01","size_bytes":4526,"line_count":81},{"path":"docs/adr/0001-product-boundary.md","sha256":"86f3513bdfa2c2c8766c6c2afdbec7b099778982e9246efe729b5d9f76da3e24","size_bytes":1151,"line_count":21},{"path":"docs/adr/0002-modular-monolith.md","sha256":"0415bc80db206f5581c758a83f09abe14bfa5e45e76fbc2b38b7bb958d2342bb","size_bytes":955,"line_count":21},{"path":"docs/adr/0003-keyverse-identity.md","sha256":"10fccb512eff2665cf0b43ef5bbef1cdf4501962e0ae353777f131a75552c309","size_bytes":865,"line_count":21},{"path":"docs/adr/0004-bitemporal-truth.md","sha256":"d7d85c1fefeed397e417653a46e1ddd2d9505740f9369d2f16769dac344d373c","size_bytes":875,"line_count":21},{"path":"docs/adr/0005-first-class-relationships.md","sha256":"1130b14f9f448d3aba40086cb1355683c0d5b4891368706c860b41e5467a5852","size_bytes":848,"line_count":21},{"path":"docs/adr/0006-provider-neutral-integrations.md","sha256":"318a12fb63ed4c788af86aa45ff1c95430f6f199bf012c1f966b073be469e7a9","size_bytes":861,"line_count":21},{"path":"docs/adr/0007-purpose-aware-privacy.md","sha256":"9ce6767604ee5787e0e2b4f051272cb7a2288be4dc8ba06e1b7bd3ffe54b0664","size_bytes":944,"line_count":21},{"path":"docs/adr/0008-ai-human-judgment.md","sha256":"1d2d14e8b6b0a03a18180a6e1a7efe9b2212afda74bd250c1c8745e5f700706d","size_bytes":950,"line_count":21},{"path":"docs/adr/0009-postgresql-system-of-record.md","sha256":"9ca96bc56d1658c933f89e3fe34b24cf0707e1b2e4862bc4929c8f4889b36bf7","size_bytes":862,"line_count":21},{"path":"docs/adr/0010-rust-compute-boundary.md","sha256":"b9e7d8f0da93a8c5f8dec5892d097c2eaab7eb4057b1a0f7a510ff22f29a5ccf","size_bytes":979,"line_count":21},{"path":"docs/adr/0011-contract-versioning.md","sha256":"76381bc76cfd59fd2a4bbd8831c217f1e6ca2625079d5c59b90d09fadc5f8afb","size_bytes":877,"line_count":21},{"path":"docs/adr/0012-quality-release-gates.md","sha256":"7083f64c1d394ad57cb8a1f19a9728b39dc032f59c6c159dabf2603751625144","size_bytes":945,"line_count":21},{"path":"docs/adr/0013-brand-and-license.md","sha256":"e27ab7029b52981abab21aacb1ed5fec8e458e1ff40163c4ab504c5426544b86","size_bytes":3160,"line_count":32},{"path":"docs/adr/0014-ux-design-system.md","sha256":"3121dfd4944a529a526a1ff3809d5c83a35360136973672f01a5d262f9a3d50a","size_bytes":977,"line_count":21},{"path":"docs/adr/0015-retention-disposition.md","sha256":"2b6b3fc4e3ddad2564e7bd9819d4aa4f980e3befb12d947ede25987a041e654c","size_bytes":915,"line_count":21},{"path":"docs/adr/0016-cwl-ecosystem-boundaries.md","sha256":"fb59ab82e8a9c5e19702412e25e22318587fd155a4dd41b14de6497b1de8066d","size_bytes":964,"line_count":21},{"path":"docs/adr/README.md","sha256":"ebd75a0c60d4dd3bd13f3135b3c81732013d8ace8ccc263b9ca7703fa406f5aa","size_bytes":1818,"line_count":22},{"path":"docs/doctoring/REFERENCES.md","sha256":"3508c3d2c9a886cb1e6fa5ed90a380e22feac730dcde737c953b1e1e04d3d5fb","size_bytes":4519,"line_count":59},{"path":"docs/doctoring/RESEARCH_BASIS.md","sha256":"1ecf6adb21fc6cfbf355fb61256c93fb20028ae228b8c910d97a867d73f184a4","size_bytes":2221,"line_count":29},{"path":"docs/doctoring/STANDARD_TRACEABILITY.md","sha256":"38d44ddfab32c0a7bf2bb7935bded795dd0a84800427e5518d64ff6a261f2314","size_bytes":2560,"line_count":22},{"path":"docs/index.md","sha256":"d7641f7c026b0bba9c7c8539b68c729517aade17de6af3656c5bf2942fded9a3","size_bytes":4611,"line_count":49},{"path":"docs/product-technical-gap-baseline.md","sha256":"34fe353d5903e29ca7c49a0e3acbc9b73637c3962c072868242adf6791ca2177","size_bytes":15753,"line_count":190},{"path":"docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md","sha256":"d453a94d4b5d2650aff49619da9733d057c5df80b241fe6a43ee0d95db99ebed","size_bytes":16116,"line_count":433},{"path":"docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md","sha256":"45debe0ac12d4648d21c0a8fb53fb9b30b07188a6b8e3ce0c9e4e22ebc34d999","size_bytes":4509,"line_count":67},{"path":"schemas/asyncapi.yaml","sha256":"b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c","size_bytes":3682,"line_count":126},{"path":"schemas/events/opportunity-stage-changed-v1.schema.json","sha256":"03c3ac79ffe93f518255401c12cc809eda31b4b5623bdc81474f44dcc8bf28b8","size_bytes":1486,"line_count":63},{"path":"schemas/events/relationship-changed-v1.schema.json","sha256":"bfcb12a02e472b74a20152a5671f5ebf18d80389a8bbe466e289873645a4945f","size_bytes":1545,"line_count":72},{"path":"schemas/openapi.yaml","sha256":"0e31e63c4c3e2bd95d58c7a17b064f106ca807a1a83d086af01641c2cfecff3b","size_bytes":13246,"line_count":504}]} +{"schema_version":"1.0","product":"ELUNVERA","generated_at":"2026-09-30T20:28:06Z","algorithm":"SHA-256","self_excluded":true,"file_count":58,"files":[{"path":".coderabbit.yaml","sha256":"efe46b993fae145eeaa2b2fb2cf0c302000c6373e5246c8e54bf330d636f4e2b","size_bytes":112,"line_count":7},{"path":".cwl/data-management.yaml","sha256":"28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671","size_bytes":1727,"line_count":48},{"path":".github/pull_request_template.md","sha256":"d7584adf5eb9866449fc5f38dc490422bf23de31ae75e1bdb385265c68122d15","size_bytes":1064,"line_count":38},{"path":".github/workflows/document-contracts.yml","sha256":"c11c08fdf8afde2d8eb80616291a587958cc404906e1c6111f2a005aa5f51269","size_bytes":10061,"line_count":215},{"path":"AGENTS.md","sha256":"6c97e76c8ec1da4d30b82a1759755bae11018c132ca0fd29d7dfc803b55006a1","size_bytes":4152,"line_count":84},{"path":"CHANGELOG.md","sha256":"ce7406b37d28ca0cfe07f7dde10acd7f46984ed3571309542544c0f48340be98","size_bytes":3848,"line_count":43},{"path":"CLAUDE.md","sha256":"67f513ae368f851201f50b6f732f444a648b3a940ca261411edbbc4c9f1ab223","size_bytes":1684,"line_count":34},{"path":"CONTRIBUTING.md","sha256":"5aee2d583ac082626a59cca4a832715ab6c9ef0e406ae48c7976887c71a74127","size_bytes":1696,"line_count":43},{"path":"LICENSE","sha256":"b7fa79459ac09645fd5bed5363852ba8759fa6deeb972d02f09fb0dc50fef586","size_bytes":11290,"line_count":192},{"path":"README.md","sha256":"3c65f74b492dfe6ae8e06eedd23a5ffde397d06b751d10a29f464c0621b77b04","size_bytes":5471,"line_count":84},{"path":"SECURITY.md","sha256":"4bfbb000844294b22ff9882211ee0a57b38e637002847cfdde8818b9276851eb","size_bytes":1091,"line_count":32},{"path":"docs/API_CONTRACT.md","sha256":"82f5d44989a1d7000dd586dde95ad71e00f52aec05d053bacbebd5f22988cfb5","size_bytes":8811,"line_count":226},{"path":"docs/ARCHITECTURE.md","sha256":"f4e39936636d48ed0d4d1c21f02562860be1af19fe8eec2d75e1d9049c30861f","size_bytes":9402,"line_count":250},{"path":"docs/DATA_MODEL.md","sha256":"3bbfe050809c960406514ff3ad0d8a273dc84b80c377189fd23f2c80f40da10a","size_bytes":15101,"line_count":504},{"path":"docs/OPERABILITY.md","sha256":"1c725823885df063bb43d8d9e4d80258ed6b9ef5029bb97cdf5100f7ec7dc80d","size_bytes":7003,"line_count":151},{"path":"docs/PRD.md","sha256":"fa61eb2cfda4013ef6d2d083b1e2ea21a307f77768e689ea5eb8f24987a6c15f","size_bytes":23521,"line_count":369},{"path":"docs/PRIVACY.md","sha256":"0599406e743af7c561208da8ad505c704ea585cebeb941444d221584aad5e004","size_bytes":6899,"line_count":141},{"path":"docs/ROADMAP.md","sha256":"3e94efa42e1553428dd90c8bd6b298b114a1af8188faa0968f690b6dd4f9a486","size_bytes":3415,"line_count":84},{"path":"docs/SECURITY.md","sha256":"d10ae9757a7233b9ce73eaa038f75939d22da4709ac6db7ee16fe4b291bd64dd","size_bytes":8100,"line_count":174},{"path":"docs/STORYBOARD.md","sha256":"c9e2d38ca25e024a7599afeff711187be272cebc7c51a9ca603846bf33bda392","size_bytes":2775,"line_count":41},{"path":"docs/STORYBOOK_INVENTORY.md","sha256":"e210ed7072720bef3b825f226419ff25dd68ee412d5272f0e5d51234b8ea4fe1","size_bytes":2354,"line_count":99},{"path":"docs/TEST_STRATEGY.md","sha256":"b1240c75308ea22db6f4c7d2e2f7ac16d11497c5d551f3c994113d6ac67f6a17","size_bytes":9456,"line_count":178},{"path":"docs/THREAT_MODEL.md","sha256":"1dc10db1d5fb0a314e25cd78c9bb1ed90b40315dbb3a32d387c2b5758910100f","size_bytes":7043,"line_count":132},{"path":"docs/TRD.md","sha256":"fa1e830ba1eecf773ea265e3d2ae620af5ab15d00f8d9ea53d8f511322934c5a","size_bytes":17622,"line_count":359},{"path":"docs/UML.md","sha256":"882a33a38bda7494e370f4135b9a3d7c5d3cf054d47cc511f3813eb046916d0c","size_bytes":3165,"line_count":115},{"path":"docs/USER_STORIES.md","sha256":"cdc8e1a2b74d7821279dfe0f07dda2d25b9bae088a720b9a6fb19270af36208c","size_bytes":3184,"line_count":37},{"path":"docs/USE_CASES.md","sha256":"4df536423c1796793edd35c200b624e6ec1daa87adf6ace9748608f24c254022","size_bytes":4357,"line_count":69},{"path":"docs/UX_SPEC.md","sha256":"e57641260cbb7ca177c773478699e03dca06b4bce3e4f994f0476187881e2919","size_bytes":8021,"line_count":178},{"path":"docs/VALIDATION_REPORT.md","sha256":"6c2356d8d0bb0da843c99547735c62aa77f72c36a5bfed5e12a4ee471d85357b","size_bytes":3010,"line_count":58},{"path":"docs/WIREFRAMES.md","sha256":"e989815acd882701ff2737036ae6f278b5a01c45081204c3c65c33c9dc0e4f01","size_bytes":4526,"line_count":81},{"path":"docs/adr/0001-product-boundary.md","sha256":"86f3513bdfa2c2c8766c6c2afdbec7b099778982e9246efe729b5d9f76da3e24","size_bytes":1151,"line_count":21},{"path":"docs/adr/0002-modular-monolith.md","sha256":"0415bc80db206f5581c758a83f09abe14bfa5e45e76fbc2b38b7bb958d2342bb","size_bytes":955,"line_count":21},{"path":"docs/adr/0003-keyverse-identity.md","sha256":"10fccb512eff2665cf0b43ef5bbef1cdf4501962e0ae353777f131a75552c309","size_bytes":865,"line_count":21},{"path":"docs/adr/0004-bitemporal-truth.md","sha256":"d7d85c1fefeed397e417653a46e1ddd2d9505740f9369d2f16769dac344d373c","size_bytes":875,"line_count":21},{"path":"docs/adr/0005-first-class-relationships.md","sha256":"1130b14f9f448d3aba40086cb1355683c0d5b4891368706c860b41e5467a5852","size_bytes":848,"line_count":21},{"path":"docs/adr/0006-provider-neutral-integrations.md","sha256":"318a12fb63ed4c788af86aa45ff1c95430f6f199bf012c1f966b073be469e7a9","size_bytes":861,"line_count":21},{"path":"docs/adr/0007-purpose-aware-privacy.md","sha256":"9ce6767604ee5787e0e2b4f051272cb7a2288be4dc8ba06e1b7bd3ffe54b0664","size_bytes":944,"line_count":21},{"path":"docs/adr/0008-ai-human-judgment.md","sha256":"1d2d14e8b6b0a03a18180a6e1a7efe9b2212afda74bd250c1c8745e5f700706d","size_bytes":950,"line_count":21},{"path":"docs/adr/0009-postgresql-system-of-record.md","sha256":"9ca96bc56d1658c933f89e3fe34b24cf0707e1b2e4862bc4929c8f4889b36bf7","size_bytes":862,"line_count":21},{"path":"docs/adr/0010-rust-compute-boundary.md","sha256":"b9e7d8f0da93a8c5f8dec5892d097c2eaab7eb4057b1a0f7a510ff22f29a5ccf","size_bytes":979,"line_count":21},{"path":"docs/adr/0011-contract-versioning.md","sha256":"76381bc76cfd59fd2a4bbd8831c217f1e6ca2625079d5c59b90d09fadc5f8afb","size_bytes":877,"line_count":21},{"path":"docs/adr/0012-quality-release-gates.md","sha256":"7083f64c1d394ad57cb8a1f19a9728b39dc032f59c6c159dabf2603751625144","size_bytes":945,"line_count":21},{"path":"docs/adr/0013-brand-and-license.md","sha256":"e27ab7029b52981abab21aacb1ed5fec8e458e1ff40163c4ab504c5426544b86","size_bytes":3160,"line_count":32},{"path":"docs/adr/0014-ux-design-system.md","sha256":"3121dfd4944a529a526a1ff3809d5c83a35360136973672f01a5d262f9a3d50a","size_bytes":977,"line_count":21},{"path":"docs/adr/0015-retention-disposition.md","sha256":"2b6b3fc4e3ddad2564e7bd9819d4aa4f980e3befb12d947ede25987a041e654c","size_bytes":915,"line_count":21},{"path":"docs/adr/0016-cwl-ecosystem-boundaries.md","sha256":"fb59ab82e8a9c5e19702412e25e22318587fd155a4dd41b14de6497b1de8066d","size_bytes":964,"line_count":21},{"path":"docs/adr/README.md","sha256":"ebd75a0c60d4dd3bd13f3135b3c81732013d8ace8ccc263b9ca7703fa406f5aa","size_bytes":1818,"line_count":22},{"path":"docs/doctoring/REFERENCES.md","sha256":"3508c3d2c9a886cb1e6fa5ed90a380e22feac730dcde737c953b1e1e04d3d5fb","size_bytes":4519,"line_count":59},{"path":"docs/doctoring/RESEARCH_BASIS.md","sha256":"1ecf6adb21fc6cfbf355fb61256c93fb20028ae228b8c910d97a867d73f184a4","size_bytes":2221,"line_count":29},{"path":"docs/doctoring/STANDARD_TRACEABILITY.md","sha256":"38d44ddfab32c0a7bf2bb7935bded795dd0a84800427e5518d64ff6a261f2314","size_bytes":2560,"line_count":22},{"path":"docs/index.md","sha256":"d7641f7c026b0bba9c7c8539b68c729517aade17de6af3656c5bf2942fded9a3","size_bytes":4611,"line_count":49},{"path":"docs/product-technical-gap-baseline.md","sha256":"7327cc5d017bd5c7f015f652f4090ad24b70495235f4f934c7bd67e375a88b55","size_bytes":16581,"line_count":248},{"path":"docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md","sha256":"d453a94d4b5d2650aff49619da9733d057c5df80b241fe6a43ee0d95db99ebed","size_bytes":16116,"line_count":433},{"path":"docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md","sha256":"45debe0ac12d4648d21c0a8fb53fb9b30b07188a6b8e3ce0c9e4e22ebc34d999","size_bytes":4509,"line_count":67},{"path":"schemas/asyncapi.yaml","sha256":"b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c","size_bytes":3682,"line_count":126},{"path":"schemas/events/opportunity-stage-changed-v1.schema.json","sha256":"03c3ac79ffe93f518255401c12cc809eda31b4b5623bdc81474f44dcc8bf28b8","size_bytes":1486,"line_count":63},{"path":"schemas/events/relationship-changed-v1.schema.json","sha256":"bfcb12a02e472b74a20152a5671f5ebf18d80389a8bbe466e289873645a4945f","size_bytes":1545,"line_count":72},{"path":"schemas/openapi.yaml","sha256":"0e31e63c4c3e2bd95d58c7a17b064f106ca807a1a83d086af01641c2cfecff3b","size_bytes":13246,"line_count":504}]} From 85f0ff3436ae614f8a6a6be427ee5bedf1869b4a Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 1 Oct 2026 05:32:45 +0900 Subject: [PATCH 86/87] fix: harden relationship evidence contract --- .github/workflows/document-contracts.yml | 10 ++++++++++ CHANGELOG.md | 1 + docs/API_CONTRACT.md | 2 ++ docs/VALIDATION_REPORT.md | 1 + manifest.json | 2 +- schemas/openapi.yaml | 8 ++++---- 6 files changed, 19 insertions(+), 5 deletions(-) diff --git a/.github/workflows/document-contracts.yml b/.github/workflows/document-contracts.yml index b176c3d..32954c8 100644 --- a/.github/workflows/document-contracts.yml +++ b/.github/workflows/document-contracts.yml @@ -60,6 +60,16 @@ jobs: raise 'OpenAPI P0 operation mismatch' unless operations.map { |method, path, _| [method, path] }.sort == expected raise 'duplicate operationId' unless operations.map(&:last).uniq.length == operations.length + relationship_request = openapi.fetch('components').fetch('schemas').fetch('RecordRelationshipRequest') + truth_status = relationship_request.fetch('properties').fetch('truth_status') + raise 'manual relationship command permits inferred truth' if truth_status.fetch('enum').include?('inferred') + evidence_refs = relationship_request.fetch('properties').fetch('evidence_reference_ids') + raise 'evidence-backed relationship accepts no evidence' unless evidence_refs['minItems'].to_i >= 1 + manual_reason = relationship_request.fetch('properties').fetch('manual_assertion_reason') + raise 'manual assertion reason must be a string' unless manual_reason['type'] == 'string' + raise 'manual assertion reason accepts empty text' unless manual_reason['minLength'].to_i >= 1 + raise 'manual assertion reason accepts whitespace only' unless manual_reason['pattern'] == '.*\\S.*' + ['/accounts', '/accounts/{account_id}'].each do |path| operation = openapi.fetch('paths').fetch(path).fetch('get') refs = operation.fetch('parameters').filter_map { |parameter| parameter['$ref'] } diff --git a/CHANGELOG.md b/CHANGELOG.md index 701c593..2636cf5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ The format follows Keep a Changelog principles, and versioning will begin when t ### Fixed +- Restricted the P0 manual relationship command to manual truth states and required non-empty evidence or a non-blank manual assertion reason. - Made the permanent document-contract gate reject trailing whitespace in committed tracked text and cleaned the affected product-technical gap baseline. - Aligned the narrative HTTP inventory with the authoritative OpenAPI P0 surface. - Added temporal read parameters and effective-lens response headers to the machine-readable HTTP contract. diff --git a/docs/API_CONTRACT.md b/docs/API_CONTRACT.md index 8074c84..ca101d2 100644 --- a/docs/API_CONTRACT.md +++ b/docs/API_CONTRACT.md @@ -128,6 +128,8 @@ POST /v1/opportunities/{opportunity_id}/stage-transitions The two account read operations accept the contract-defined `valid_at`, `recorded_at`, and `knowledge_cutoff` parameters and echo the effective temporal lens in response headers. Mutations require `X-Correlation-Id` and `Idempotency-Key`; updates to an existing aggregate also require `If-Match`. +The manual relationship command accepts `authoritative`, `observed`, or `proposed` truth only. It requires either at least one evidence reference or a non-blank manual assertion reason. Inferred truth belongs to a separately governed inference path that supplies evidence, confidence, and confidence-method metadata; the manual P0 command cannot manufacture it. + Parties, interactions, commitments, relationship review, account merge/split, customer outcomes, complaints, satisfaction observations, search, model jobs, privacy cases, disposition, legal hold, and audit-query operations remain product-roadmap candidates. They are **not** HTTP contract commitments until their operations and schemas are added to `schemas/openapi.yaml`, validated, and versioned. Model-related future operations must return evidence references, uncertainty, model identity, prompt hash, and review status. A model claim can never mutate authoritative CRM facts without an explicit human-reviewed command. diff --git a/docs/VALIDATION_REPORT.md b/docs/VALIDATION_REPORT.md index 2f87704..1ef9470 100644 --- a/docs/VALIDATION_REPORT.md +++ b/docs/VALIDATION_REPORT.md @@ -17,6 +17,7 @@ | YAML parsing | Pass | | OpenAPI version and unique `operationId` structure | Pass | | Narrative/OpenAPI operation parity for the contract-bearing P0 surface | Pass | +| Manual relationship truth and evidence invariants | Pass | | Temporal query parameters and effective-lens response headers | Pass | | AsyncAPI version, channel, producer-operation direction, and message structure | Pass | | Required event classification and payload-schema revision metadata | Pass | diff --git a/manifest.json b/manifest.json index f3ab623..5d7a117 100644 --- a/manifest.json +++ b/manifest.json @@ -1 +1 @@ -{"schema_version":"1.0","product":"ELUNVERA","generated_at":"2026-09-30T20:28:06Z","algorithm":"SHA-256","self_excluded":true,"file_count":58,"files":[{"path":".coderabbit.yaml","sha256":"efe46b993fae145eeaa2b2fb2cf0c302000c6373e5246c8e54bf330d636f4e2b","size_bytes":112,"line_count":7},{"path":".cwl/data-management.yaml","sha256":"28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671","size_bytes":1727,"line_count":48},{"path":".github/pull_request_template.md","sha256":"d7584adf5eb9866449fc5f38dc490422bf23de31ae75e1bdb385265c68122d15","size_bytes":1064,"line_count":38},{"path":".github/workflows/document-contracts.yml","sha256":"c11c08fdf8afde2d8eb80616291a587958cc404906e1c6111f2a005aa5f51269","size_bytes":10061,"line_count":215},{"path":"AGENTS.md","sha256":"6c97e76c8ec1da4d30b82a1759755bae11018c132ca0fd29d7dfc803b55006a1","size_bytes":4152,"line_count":84},{"path":"CHANGELOG.md","sha256":"ce7406b37d28ca0cfe07f7dde10acd7f46984ed3571309542544c0f48340be98","size_bytes":3848,"line_count":43},{"path":"CLAUDE.md","sha256":"67f513ae368f851201f50b6f732f444a648b3a940ca261411edbbc4c9f1ab223","size_bytes":1684,"line_count":34},{"path":"CONTRIBUTING.md","sha256":"5aee2d583ac082626a59cca4a832715ab6c9ef0e406ae48c7976887c71a74127","size_bytes":1696,"line_count":43},{"path":"LICENSE","sha256":"b7fa79459ac09645fd5bed5363852ba8759fa6deeb972d02f09fb0dc50fef586","size_bytes":11290,"line_count":192},{"path":"README.md","sha256":"3c65f74b492dfe6ae8e06eedd23a5ffde397d06b751d10a29f464c0621b77b04","size_bytes":5471,"line_count":84},{"path":"SECURITY.md","sha256":"4bfbb000844294b22ff9882211ee0a57b38e637002847cfdde8818b9276851eb","size_bytes":1091,"line_count":32},{"path":"docs/API_CONTRACT.md","sha256":"82f5d44989a1d7000dd586dde95ad71e00f52aec05d053bacbebd5f22988cfb5","size_bytes":8811,"line_count":226},{"path":"docs/ARCHITECTURE.md","sha256":"f4e39936636d48ed0d4d1c21f02562860be1af19fe8eec2d75e1d9049c30861f","size_bytes":9402,"line_count":250},{"path":"docs/DATA_MODEL.md","sha256":"3bbfe050809c960406514ff3ad0d8a273dc84b80c377189fd23f2c80f40da10a","size_bytes":15101,"line_count":504},{"path":"docs/OPERABILITY.md","sha256":"1c725823885df063bb43d8d9e4d80258ed6b9ef5029bb97cdf5100f7ec7dc80d","size_bytes":7003,"line_count":151},{"path":"docs/PRD.md","sha256":"fa61eb2cfda4013ef6d2d083b1e2ea21a307f77768e689ea5eb8f24987a6c15f","size_bytes":23521,"line_count":369},{"path":"docs/PRIVACY.md","sha256":"0599406e743af7c561208da8ad505c704ea585cebeb941444d221584aad5e004","size_bytes":6899,"line_count":141},{"path":"docs/ROADMAP.md","sha256":"3e94efa42e1553428dd90c8bd6b298b114a1af8188faa0968f690b6dd4f9a486","size_bytes":3415,"line_count":84},{"path":"docs/SECURITY.md","sha256":"d10ae9757a7233b9ce73eaa038f75939d22da4709ac6db7ee16fe4b291bd64dd","size_bytes":8100,"line_count":174},{"path":"docs/STORYBOARD.md","sha256":"c9e2d38ca25e024a7599afeff711187be272cebc7c51a9ca603846bf33bda392","size_bytes":2775,"line_count":41},{"path":"docs/STORYBOOK_INVENTORY.md","sha256":"e210ed7072720bef3b825f226419ff25dd68ee412d5272f0e5d51234b8ea4fe1","size_bytes":2354,"line_count":99},{"path":"docs/TEST_STRATEGY.md","sha256":"b1240c75308ea22db6f4c7d2e2f7ac16d11497c5d551f3c994113d6ac67f6a17","size_bytes":9456,"line_count":178},{"path":"docs/THREAT_MODEL.md","sha256":"1dc10db1d5fb0a314e25cd78c9bb1ed90b40315dbb3a32d387c2b5758910100f","size_bytes":7043,"line_count":132},{"path":"docs/TRD.md","sha256":"fa1e830ba1eecf773ea265e3d2ae620af5ab15d00f8d9ea53d8f511322934c5a","size_bytes":17622,"line_count":359},{"path":"docs/UML.md","sha256":"882a33a38bda7494e370f4135b9a3d7c5d3cf054d47cc511f3813eb046916d0c","size_bytes":3165,"line_count":115},{"path":"docs/USER_STORIES.md","sha256":"cdc8e1a2b74d7821279dfe0f07dda2d25b9bae088a720b9a6fb19270af36208c","size_bytes":3184,"line_count":37},{"path":"docs/USE_CASES.md","sha256":"4df536423c1796793edd35c200b624e6ec1daa87adf6ace9748608f24c254022","size_bytes":4357,"line_count":69},{"path":"docs/UX_SPEC.md","sha256":"e57641260cbb7ca177c773478699e03dca06b4bce3e4f994f0476187881e2919","size_bytes":8021,"line_count":178},{"path":"docs/VALIDATION_REPORT.md","sha256":"6c2356d8d0bb0da843c99547735c62aa77f72c36a5bfed5e12a4ee471d85357b","size_bytes":3010,"line_count":58},{"path":"docs/WIREFRAMES.md","sha256":"e989815acd882701ff2737036ae6f278b5a01c45081204c3c65c33c9dc0e4f01","size_bytes":4526,"line_count":81},{"path":"docs/adr/0001-product-boundary.md","sha256":"86f3513bdfa2c2c8766c6c2afdbec7b099778982e9246efe729b5d9f76da3e24","size_bytes":1151,"line_count":21},{"path":"docs/adr/0002-modular-monolith.md","sha256":"0415bc80db206f5581c758a83f09abe14bfa5e45e76fbc2b38b7bb958d2342bb","size_bytes":955,"line_count":21},{"path":"docs/adr/0003-keyverse-identity.md","sha256":"10fccb512eff2665cf0b43ef5bbef1cdf4501962e0ae353777f131a75552c309","size_bytes":865,"line_count":21},{"path":"docs/adr/0004-bitemporal-truth.md","sha256":"d7d85c1fefeed397e417653a46e1ddd2d9505740f9369d2f16769dac344d373c","size_bytes":875,"line_count":21},{"path":"docs/adr/0005-first-class-relationships.md","sha256":"1130b14f9f448d3aba40086cb1355683c0d5b4891368706c860b41e5467a5852","size_bytes":848,"line_count":21},{"path":"docs/adr/0006-provider-neutral-integrations.md","sha256":"318a12fb63ed4c788af86aa45ff1c95430f6f199bf012c1f966b073be469e7a9","size_bytes":861,"line_count":21},{"path":"docs/adr/0007-purpose-aware-privacy.md","sha256":"9ce6767604ee5787e0e2b4f051272cb7a2288be4dc8ba06e1b7bd3ffe54b0664","size_bytes":944,"line_count":21},{"path":"docs/adr/0008-ai-human-judgment.md","sha256":"1d2d14e8b6b0a03a18180a6e1a7efe9b2212afda74bd250c1c8745e5f700706d","size_bytes":950,"line_count":21},{"path":"docs/adr/0009-postgresql-system-of-record.md","sha256":"9ca96bc56d1658c933f89e3fe34b24cf0707e1b2e4862bc4929c8f4889b36bf7","size_bytes":862,"line_count":21},{"path":"docs/adr/0010-rust-compute-boundary.md","sha256":"b9e7d8f0da93a8c5f8dec5892d097c2eaab7eb4057b1a0f7a510ff22f29a5ccf","size_bytes":979,"line_count":21},{"path":"docs/adr/0011-contract-versioning.md","sha256":"76381bc76cfd59fd2a4bbd8831c217f1e6ca2625079d5c59b90d09fadc5f8afb","size_bytes":877,"line_count":21},{"path":"docs/adr/0012-quality-release-gates.md","sha256":"7083f64c1d394ad57cb8a1f19a9728b39dc032f59c6c159dabf2603751625144","size_bytes":945,"line_count":21},{"path":"docs/adr/0013-brand-and-license.md","sha256":"e27ab7029b52981abab21aacb1ed5fec8e458e1ff40163c4ab504c5426544b86","size_bytes":3160,"line_count":32},{"path":"docs/adr/0014-ux-design-system.md","sha256":"3121dfd4944a529a526a1ff3809d5c83a35360136973672f01a5d262f9a3d50a","size_bytes":977,"line_count":21},{"path":"docs/adr/0015-retention-disposition.md","sha256":"2b6b3fc4e3ddad2564e7bd9819d4aa4f980e3befb12d947ede25987a041e654c","size_bytes":915,"line_count":21},{"path":"docs/adr/0016-cwl-ecosystem-boundaries.md","sha256":"fb59ab82e8a9c5e19702412e25e22318587fd155a4dd41b14de6497b1de8066d","size_bytes":964,"line_count":21},{"path":"docs/adr/README.md","sha256":"ebd75a0c60d4dd3bd13f3135b3c81732013d8ace8ccc263b9ca7703fa406f5aa","size_bytes":1818,"line_count":22},{"path":"docs/doctoring/REFERENCES.md","sha256":"3508c3d2c9a886cb1e6fa5ed90a380e22feac730dcde737c953b1e1e04d3d5fb","size_bytes":4519,"line_count":59},{"path":"docs/doctoring/RESEARCH_BASIS.md","sha256":"1ecf6adb21fc6cfbf355fb61256c93fb20028ae228b8c910d97a867d73f184a4","size_bytes":2221,"line_count":29},{"path":"docs/doctoring/STANDARD_TRACEABILITY.md","sha256":"38d44ddfab32c0a7bf2bb7935bded795dd0a84800427e5518d64ff6a261f2314","size_bytes":2560,"line_count":22},{"path":"docs/index.md","sha256":"d7641f7c026b0bba9c7c8539b68c729517aade17de6af3656c5bf2942fded9a3","size_bytes":4611,"line_count":49},{"path":"docs/product-technical-gap-baseline.md","sha256":"7327cc5d017bd5c7f015f652f4090ad24b70495235f4f934c7bd67e375a88b55","size_bytes":16581,"line_count":248},{"path":"docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md","sha256":"d453a94d4b5d2650aff49619da9733d057c5df80b241fe6a43ee0d95db99ebed","size_bytes":16116,"line_count":433},{"path":"docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md","sha256":"45debe0ac12d4648d21c0a8fb53fb9b30b07188a6b8e3ce0c9e4e22ebc34d999","size_bytes":4509,"line_count":67},{"path":"schemas/asyncapi.yaml","sha256":"b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c","size_bytes":3682,"line_count":126},{"path":"schemas/events/opportunity-stage-changed-v1.schema.json","sha256":"03c3ac79ffe93f518255401c12cc809eda31b4b5623bdc81474f44dcc8bf28b8","size_bytes":1486,"line_count":63},{"path":"schemas/events/relationship-changed-v1.schema.json","sha256":"bfcb12a02e472b74a20152a5671f5ebf18d80389a8bbe466e289873645a4945f","size_bytes":1545,"line_count":72},{"path":"schemas/openapi.yaml","sha256":"0e31e63c4c3e2bd95d58c7a17b064f106ca807a1a83d086af01641c2cfecff3b","size_bytes":13246,"line_count":504}]} +{"schema_version":"1.0","product":"ELUNVERA","generated_at":"2026-09-30T20:31:30Z","algorithm":"SHA-256","self_excluded":true,"file_count":58,"files":[{"path":".coderabbit.yaml","sha256":"efe46b993fae145eeaa2b2fb2cf0c302000c6373e5246c8e54bf330d636f4e2b","size_bytes":112,"line_count":7},{"path":".cwl/data-management.yaml","sha256":"28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671","size_bytes":1727,"line_count":48},{"path":".github/pull_request_template.md","sha256":"d7584adf5eb9866449fc5f38dc490422bf23de31ae75e1bdb385265c68122d15","size_bytes":1064,"line_count":38},{"path":".github/workflows/document-contracts.yml","sha256":"a28db289bf927a8eaf441bb89ccc49e7146c98bea6e025a6ffbb1c8fb70ea8be","size_bytes":11008,"line_count":225},{"path":"AGENTS.md","sha256":"6c97e76c8ec1da4d30b82a1759755bae11018c132ca0fd29d7dfc803b55006a1","size_bytes":4152,"line_count":84},{"path":"CHANGELOG.md","sha256":"48d234ba74a97edc4d899db91b13dead2baac8ad3354212f4a756eadcb95ef20","size_bytes":3991,"line_count":44},{"path":"CLAUDE.md","sha256":"67f513ae368f851201f50b6f732f444a648b3a940ca261411edbbc4c9f1ab223","size_bytes":1684,"line_count":34},{"path":"CONTRIBUTING.md","sha256":"5aee2d583ac082626a59cca4a832715ab6c9ef0e406ae48c7976887c71a74127","size_bytes":1696,"line_count":43},{"path":"LICENSE","sha256":"b7fa79459ac09645fd5bed5363852ba8759fa6deeb972d02f09fb0dc50fef586","size_bytes":11290,"line_count":192},{"path":"README.md","sha256":"3c65f74b492dfe6ae8e06eedd23a5ffde397d06b751d10a29f464c0621b77b04","size_bytes":5471,"line_count":84},{"path":"SECURITY.md","sha256":"4bfbb000844294b22ff9882211ee0a57b38e637002847cfdde8818b9276851eb","size_bytes":1091,"line_count":32},{"path":"docs/API_CONTRACT.md","sha256":"8140d7fdad34c28767892a4e5920d3ad42d3f429f0cf0fa07a0c4f219911d4a8","size_bytes":9174,"line_count":228},{"path":"docs/ARCHITECTURE.md","sha256":"f4e39936636d48ed0d4d1c21f02562860be1af19fe8eec2d75e1d9049c30861f","size_bytes":9402,"line_count":250},{"path":"docs/DATA_MODEL.md","sha256":"3bbfe050809c960406514ff3ad0d8a273dc84b80c377189fd23f2c80f40da10a","size_bytes":15101,"line_count":504},{"path":"docs/OPERABILITY.md","sha256":"1c725823885df063bb43d8d9e4d80258ed6b9ef5029bb97cdf5100f7ec7dc80d","size_bytes":7003,"line_count":151},{"path":"docs/PRD.md","sha256":"fa61eb2cfda4013ef6d2d083b1e2ea21a307f77768e689ea5eb8f24987a6c15f","size_bytes":23521,"line_count":369},{"path":"docs/PRIVACY.md","sha256":"0599406e743af7c561208da8ad505c704ea585cebeb941444d221584aad5e004","size_bytes":6899,"line_count":141},{"path":"docs/ROADMAP.md","sha256":"3e94efa42e1553428dd90c8bd6b298b114a1af8188faa0968f690b6dd4f9a486","size_bytes":3415,"line_count":84},{"path":"docs/SECURITY.md","sha256":"d10ae9757a7233b9ce73eaa038f75939d22da4709ac6db7ee16fe4b291bd64dd","size_bytes":8100,"line_count":174},{"path":"docs/STORYBOARD.md","sha256":"c9e2d38ca25e024a7599afeff711187be272cebc7c51a9ca603846bf33bda392","size_bytes":2775,"line_count":41},{"path":"docs/STORYBOOK_INVENTORY.md","sha256":"e210ed7072720bef3b825f226419ff25dd68ee412d5272f0e5d51234b8ea4fe1","size_bytes":2354,"line_count":99},{"path":"docs/TEST_STRATEGY.md","sha256":"b1240c75308ea22db6f4c7d2e2f7ac16d11497c5d551f3c994113d6ac67f6a17","size_bytes":9456,"line_count":178},{"path":"docs/THREAT_MODEL.md","sha256":"1dc10db1d5fb0a314e25cd78c9bb1ed90b40315dbb3a32d387c2b5758910100f","size_bytes":7043,"line_count":132},{"path":"docs/TRD.md","sha256":"fa1e830ba1eecf773ea265e3d2ae620af5ab15d00f8d9ea53d8f511322934c5a","size_bytes":17622,"line_count":359},{"path":"docs/UML.md","sha256":"882a33a38bda7494e370f4135b9a3d7c5d3cf054d47cc511f3813eb046916d0c","size_bytes":3165,"line_count":115},{"path":"docs/USER_STORIES.md","sha256":"cdc8e1a2b74d7821279dfe0f07dda2d25b9bae088a720b9a6fb19270af36208c","size_bytes":3184,"line_count":37},{"path":"docs/USE_CASES.md","sha256":"4df536423c1796793edd35c200b624e6ec1daa87adf6ace9748608f24c254022","size_bytes":4357,"line_count":69},{"path":"docs/UX_SPEC.md","sha256":"e57641260cbb7ca177c773478699e03dca06b4bce3e4f994f0476187881e2919","size_bytes":8021,"line_count":178},{"path":"docs/VALIDATION_REPORT.md","sha256":"2e9d563bb02dea4a8c62b7f8c0c1fca22457ae6304bcd8d2436caeb96321a49d","size_bytes":3071,"line_count":59},{"path":"docs/WIREFRAMES.md","sha256":"e989815acd882701ff2737036ae6f278b5a01c45081204c3c65c33c9dc0e4f01","size_bytes":4526,"line_count":81},{"path":"docs/adr/0001-product-boundary.md","sha256":"86f3513bdfa2c2c8766c6c2afdbec7b099778982e9246efe729b5d9f76da3e24","size_bytes":1151,"line_count":21},{"path":"docs/adr/0002-modular-monolith.md","sha256":"0415bc80db206f5581c758a83f09abe14bfa5e45e76fbc2b38b7bb958d2342bb","size_bytes":955,"line_count":21},{"path":"docs/adr/0003-keyverse-identity.md","sha256":"10fccb512eff2665cf0b43ef5bbef1cdf4501962e0ae353777f131a75552c309","size_bytes":865,"line_count":21},{"path":"docs/adr/0004-bitemporal-truth.md","sha256":"d7d85c1fefeed397e417653a46e1ddd2d9505740f9369d2f16769dac344d373c","size_bytes":875,"line_count":21},{"path":"docs/adr/0005-first-class-relationships.md","sha256":"1130b14f9f448d3aba40086cb1355683c0d5b4891368706c860b41e5467a5852","size_bytes":848,"line_count":21},{"path":"docs/adr/0006-provider-neutral-integrations.md","sha256":"318a12fb63ed4c788af86aa45ff1c95430f6f199bf012c1f966b073be469e7a9","size_bytes":861,"line_count":21},{"path":"docs/adr/0007-purpose-aware-privacy.md","sha256":"9ce6767604ee5787e0e2b4f051272cb7a2288be4dc8ba06e1b7bd3ffe54b0664","size_bytes":944,"line_count":21},{"path":"docs/adr/0008-ai-human-judgment.md","sha256":"1d2d14e8b6b0a03a18180a6e1a7efe9b2212afda74bd250c1c8745e5f700706d","size_bytes":950,"line_count":21},{"path":"docs/adr/0009-postgresql-system-of-record.md","sha256":"9ca96bc56d1658c933f89e3fe34b24cf0707e1b2e4862bc4929c8f4889b36bf7","size_bytes":862,"line_count":21},{"path":"docs/adr/0010-rust-compute-boundary.md","sha256":"b9e7d8f0da93a8c5f8dec5892d097c2eaab7eb4057b1a0f7a510ff22f29a5ccf","size_bytes":979,"line_count":21},{"path":"docs/adr/0011-contract-versioning.md","sha256":"76381bc76cfd59fd2a4bbd8831c217f1e6ca2625079d5c59b90d09fadc5f8afb","size_bytes":877,"line_count":21},{"path":"docs/adr/0012-quality-release-gates.md","sha256":"7083f64c1d394ad57cb8a1f19a9728b39dc032f59c6c159dabf2603751625144","size_bytes":945,"line_count":21},{"path":"docs/adr/0013-brand-and-license.md","sha256":"e27ab7029b52981abab21aacb1ed5fec8e458e1ff40163c4ab504c5426544b86","size_bytes":3160,"line_count":32},{"path":"docs/adr/0014-ux-design-system.md","sha256":"3121dfd4944a529a526a1ff3809d5c83a35360136973672f01a5d262f9a3d50a","size_bytes":977,"line_count":21},{"path":"docs/adr/0015-retention-disposition.md","sha256":"2b6b3fc4e3ddad2564e7bd9819d4aa4f980e3befb12d947ede25987a041e654c","size_bytes":915,"line_count":21},{"path":"docs/adr/0016-cwl-ecosystem-boundaries.md","sha256":"fb59ab82e8a9c5e19702412e25e22318587fd155a4dd41b14de6497b1de8066d","size_bytes":964,"line_count":21},{"path":"docs/adr/README.md","sha256":"ebd75a0c60d4dd3bd13f3135b3c81732013d8ace8ccc263b9ca7703fa406f5aa","size_bytes":1818,"line_count":22},{"path":"docs/doctoring/REFERENCES.md","sha256":"3508c3d2c9a886cb1e6fa5ed90a380e22feac730dcde737c953b1e1e04d3d5fb","size_bytes":4519,"line_count":59},{"path":"docs/doctoring/RESEARCH_BASIS.md","sha256":"1ecf6adb21fc6cfbf355fb61256c93fb20028ae228b8c910d97a867d73f184a4","size_bytes":2221,"line_count":29},{"path":"docs/doctoring/STANDARD_TRACEABILITY.md","sha256":"38d44ddfab32c0a7bf2bb7935bded795dd0a84800427e5518d64ff6a261f2314","size_bytes":2560,"line_count":22},{"path":"docs/index.md","sha256":"d7641f7c026b0bba9c7c8539b68c729517aade17de6af3656c5bf2942fded9a3","size_bytes":4611,"line_count":49},{"path":"docs/product-technical-gap-baseline.md","sha256":"7327cc5d017bd5c7f015f652f4090ad24b70495235f4f934c7bd67e375a88b55","size_bytes":16581,"line_count":248},{"path":"docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md","sha256":"d453a94d4b5d2650aff49619da9733d057c5df80b241fe6a43ee0d95db99ebed","size_bytes":16116,"line_count":433},{"path":"docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md","sha256":"45debe0ac12d4648d21c0a8fb53fb9b30b07188a6b8e3ce0c9e4e22ebc34d999","size_bytes":4509,"line_count":67},{"path":"schemas/asyncapi.yaml","sha256":"b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c","size_bytes":3682,"line_count":126},{"path":"schemas/events/opportunity-stage-changed-v1.schema.json","sha256":"03c3ac79ffe93f518255401c12cc809eda31b4b5623bdc81474f44dcc8bf28b8","size_bytes":1486,"line_count":63},{"path":"schemas/events/relationship-changed-v1.schema.json","sha256":"bfcb12a02e472b74a20152a5671f5ebf18d80389a8bbe466e289873645a4945f","size_bytes":1545,"line_count":72},{"path":"schemas/openapi.yaml","sha256":"795ad75441d033a0f80dfe5a054328110858886929d10a02dc1c36dee5039781","size_bytes":13265,"line_count":504}]} diff --git a/schemas/openapi.yaml b/schemas/openapi.yaml index 672a16e..77cf8c9 100644 --- a/schemas/openapi.yaml +++ b/schemas/openapi.yaml @@ -380,19 +380,19 @@ components: enum: - authoritative - observed - - inferred - proposed evidence_reference_ids: type: array + minItems: 1 maxItems: 100 items: type: string format: uuid manual_assertion_reason: - type: - - string - - 'null' + type: string + minLength: 1 maxLength: 1000 + pattern: .*\S.* anyOf: - required: - evidence_reference_ids From 5a514422344d6027d7eb135b660e2dab01379529 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Thu, 1 Oct 2026 06:15:54 +0900 Subject: [PATCH 87/87] fix: address exact-head contract review --- .github/workflows/document-contracts.yml | 37 +++++++++++++++++++ docs/DATA_MODEL.md | 8 ++-- docs/STORYBOOK_INVENTORY.md | 6 +++ docs/UML.md | 19 +++++++--- ...elunvera-foundation-implementation-plan.md | 24 ++++++++---- manifest.json | 2 +- schemas/openapi.yaml | 1 + 7 files changed, 78 insertions(+), 19 deletions(-) diff --git a/.github/workflows/document-contracts.yml b/.github/workflows/document-contracts.yml index 32954c8..9425533 100644 --- a/.github/workflows/document-contracts.yml +++ b/.github/workflows/document-contracts.yml @@ -70,6 +70,9 @@ jobs: raise 'manual assertion reason accepts empty text' unless manual_reason['minLength'].to_i >= 1 raise 'manual assertion reason accepts whitespace only' unless manual_reason['pattern'] == '.*\\S.*' + account_items = openapi.fetch('components').fetch('schemas').fetch('AccountPage').fetch('properties').fetch('items') + raise 'AccountPage items must be bounded to page_size maximum' unless account_items['maxItems'] == 100 + ['/accounts', '/accounts/{account_id}'].each do |path| operation = openapi.fetch('paths').fetch(path).fetch('get') refs = operation.fetch('parameters').filter_map { |parameter| parameter['$ref'] } @@ -149,12 +152,46 @@ jobs: 'p95 ≤ 20 ms', 'ko/en/ja/zh/vi/es/de/fr', ), + Path('docs/DATA_MODEL.md'): ( + 'party_record ||--o| person_party : specializes', + 'party_record ||--o| organization_party : specializes', + 'party_record ||--o| group_party : specializes', + 'Exactly one party subtype record must exist and match `party_kind_code`.', + ), + Path('docs/STORYBOOK_INVENTORY.md'): ( + 'Japanese', + 'Chinese', + 'Vietnamese', + 'Spanish', + 'German', + 'French', + ), + Path('docs/UML.md'): ( + 'Acknowledged --> Triaged', + 'Investigating --> ResponseProposed', + 'RemedyInProgress --> VerificationPending', + 'Rejected --> Reopened', + ), + Path('docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md'): ( + 'Consumes: a Keyverse token verifier', + 'incorrect issuer, audience, signature, token type, applicable nonce', + 'ko/en/ja/zh/vi/es/de/fr', + ), } for path, markers in product_contract_markers.items(): text = path.read_text(encoding='utf-8') for marker in markers: assert marker in text, f'commercialization contract drift: {path}: {marker}' + plan_text = Path('docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md').read_text(encoding='utf-8') + assert plan_text.count('cargo +nightly llvm-cov') == 3 + assert plan_text.count("branches['count'] == branches['covered']") == 3 + assert 'cargo llvm-cov --workspace --branch' not in plan_text + uml_text = Path('docs/UML.md').read_text(encoding='utf-8') + assert 'RemedyProposed' not in uml_text + assert 'RemedyDelivered' not in uml_text + assert 'FollowUp' not in uml_text + for event_path in ( Path('schemas/events/relationship-changed-v1.schema.json'), Path('schemas/events/opportunity-stage-changed-v1.schema.json'), diff --git a/docs/DATA_MODEL.md b/docs/DATA_MODEL.md index cf8cbb3..0ab57d9 100644 --- a/docs/DATA_MODEL.md +++ b/docs/DATA_MODEL.md @@ -29,9 +29,9 @@ erDiagram tenant_account ||--o{ workspace_record : contains tenant_account ||--o{ party_record : owns tenant_account ||--o{ commercial_account : owns - party_record ||--|| person_party : specializes - party_record ||--|| organization_party : specializes - party_record ||--|| group_party : specializes + party_record ||--o| person_party : specializes + party_record ||--o| organization_party : specializes + party_record ||--o| group_party : specializes commercial_account }o--|| party_record : centers_on commercial_account ||--o{ account_role_assignment : has @@ -107,7 +107,7 @@ created_at updated_at ``` -The `party_kind_code` is structural (`person`, `organization`, `group`), not a commercial role such as customer or partner. +The `party_kind_code` is structural (`person`, `organization`, `group`), not a commercial role such as customer or partner. Exactly one party subtype record must exist and match `party_kind_code`. ### Type extensions diff --git a/docs/STORYBOOK_INVENTORY.md b/docs/STORYBOOK_INVENTORY.md index 191f13a..b4d0562 100644 --- a/docs/STORYBOOK_INVENTORY.md +++ b/docs/STORYBOOK_INVENTORY.md @@ -74,6 +74,12 @@ high zoom reduced motion Korean English +Japanese +Chinese +Vietnamese +Spanish +German +French print ``` diff --git a/docs/UML.md b/docs/UML.md index 24c03a3..e07e4c4 100644 --- a/docs/UML.md +++ b/docs/UML.md @@ -89,13 +89,20 @@ The actual stages and allowed transitions are versioned per tenant. This diagram stateDiagram-v2 [*] --> Received Received --> Acknowledged - Acknowledged --> Investigating - Investigating --> RemedyProposed - RemedyProposed --> RemedyDelivered - RemedyDelivered --> FollowUp - FollowUp --> Closed + Acknowledged --> Triaged + Triaged --> Investigating + Investigating --> ResponseProposed + ResponseProposed --> Responded + Responded --> RemedyInProgress + RemedyInProgress --> VerificationPending + VerificationPending --> Closed Received --> Withdrawn - Investigating --> Withdrawn + Acknowledged --> Withdrawn + Triaged --> Rejected + Investigating --> Rejected + Closed --> Reopened + Rejected --> Reopened + Reopened --> Triaged ``` ## 6. Truth-status state model diff --git a/docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md b/docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md index 9a38939..58892c5 100644 --- a/docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md +++ b/docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md @@ -110,8 +110,9 @@ git commit -m "build: establish Rust foundation quality gate" **Interfaces:** - Produces: `VerifiedRequestContext`, `TenantReference`, `PurposeCode`, `AuthorizationError`. +- Consumes: a Keyverse token verifier that validates the token before context construction. -- [ ] **Step 1: Write failing context tests** +- [ ] **Step 1: Write failing context and token-validation tests** ```rust #[test] @@ -127,6 +128,8 @@ fn missing_purpose_is_rejected() { } ``` +Reject an incorrect issuer, audience, signature, token type, applicable nonce, `nbf`, `iat`, or `exp` before constructing `VerifiedRequestContext`. + - [ ] **Step 2: Verify RED** Run: `cargo test -p authorization_context` @@ -134,7 +137,7 @@ Expected: compilation failure because the types do not exist. - [ ] **Step 3: Implement immutable typed context** -Use private fields, validated constructors, opaque tenant/workspace references, bounded role/scope sets, UTC time checks, and no deserialization path that accepts authority directly from HTTP headers. +Validate the Keyverse token before constructing `VerifiedRequestContext`. Use private fields, validated constructors, opaque tenant/workspace references, bounded role/scope sets, UTC time checks, and no deserialization path that accepts authority directly from HTTP headers. - [ ] **Step 4: Verify GREEN and coverage** @@ -142,7 +145,8 @@ Run: ```bash cargo test -p authorization_context -cargo llvm-cov -p authorization_context --branch --fail-under-lines 100 --fail-under-functions 100 --fail-under-regions 100 +cargo +nightly llvm-cov -p authorization_context --branch --json --output-path target/llvm-cov-target/coverage.json --fail-under-lines 100 --fail-under-functions 100 --fail-under-regions 100 +python -c "import json; branches = json.load(open('target/llvm-cov-target/coverage.json'))['data'][0]['totals']['branches']; assert branches['count'] == branches['covered'], branches" ``` Expected: all tests pass and production coverage is complete. @@ -236,7 +240,8 @@ Run: ```bash cargo test -p account_registry -p party_registry -p relationship_registry -cargo llvm-cov --workspace --branch --fail-under-lines 100 +cargo +nightly llvm-cov --workspace --branch --json --output-path target/llvm-cov-target/coverage.json --fail-under-lines 100 +python -c "import json; branches = json.load(open('target/llvm-cov-target/coverage.json'))['data'][0]['totals']['branches']; assert branches['count'] == branches['covered'], branches" ``` Expected: all state transitions, negative branches, and production lines pass. @@ -343,11 +348,11 @@ git commit -m "feat: project account context from durable events" - [ ] **Step 1: Create and record the Figma library** -Create reviewed desktop, tablet, mobile, Korean, English, print, loading, empty, stale, conflict, denied, and provider-unavailable frames. Record the real Figma File ID in ADR-0014; do not use a placeholder. +Create reviewed desktop, tablet, mobile, Korean (`ko`), English (`en`), Japanese (`ja`), Chinese (`zh`), Vietnamese (`vi`), Spanish (`es`), German (`de`), French (`fr`), print, loading, empty, stale, conflict, denied, and provider-unavailable frames. Record the real Figma File ID in ADR-0014; do not use a placeholder. - [ ] **Step 2: Write failing Storybook and Playwright interactions** -Test keyboard band navigation, evidence drawer focus, graph-to-table parity, Korean/English rendering, stale state, safe next-action copy, and print exact values. +Test keyboard band navigation, evidence drawer focus, graph-to-table parity, `ko/en/ja/zh/vi/es/de/fr` rendering, stale state, safe next-action copy, and print exact values. - [ ] **Step 3: Verify RED** @@ -367,6 +372,8 @@ Use accessible semantic HTML, progressive enhancement, bounded graph rendering, - [ ] **Step 5: Validate screenshots and accessibility, then commit** +Do not mark Task 7 complete until Storybook, E2E, and screenshot evidence covers `ko/en/ja/zh/vi/es/de/fr`. + ```bash pnpm --dir apps/elunvera_web lint pnpm --dir apps/elunvera_web typecheck @@ -412,7 +419,8 @@ Add low-cardinality metrics, correlation propagation, bounded status output, gra cargo fmt --all -- --check cargo clippy --workspace --all-targets --all-features -- -D warnings cargo nextest run --workspace --all-features -cargo llvm-cov --workspace --branch --fail-under-lines 100 +cargo +nightly llvm-cov --workspace --branch --json --output-path target/llvm-cov-target/coverage.json --fail-under-lines 100 +python -c "import json; branches = json.load(open('target/llvm-cov-target/coverage.json'))['data'][0]['totals']['branches']; assert branches['count'] == branches['covered'], branches" python scripts/validate-contracts.py ./scripts/rehearse-migrations.sh ./scripts/rehearse-restore.sh @@ -430,4 +438,4 @@ git commit -m "ops: complete ELUNVERA foundation readiness evidence" ## Plan completion gate -The foundation is complete only when a target user can authenticate, create an account and parties, record and correct an evidence-linked time-valid relationship, view the accessible three-band account page, inspect the audit and operation receipt, and recover the same result from a tested backup without crossing tenant boundaries. +The foundation is complete only when a target user can authenticate, create an account and parties, record and correct an evidence-linked time-valid relationship, view the accessible three-band account page, inspect the audit and operation receipt, and recover the same result from a tested backup without crossing tenant boundaries. Completion also requires reviewed Storybook, E2E, and screenshot evidence for `ko/en/ja/zh/vi/es/de/fr`. diff --git a/manifest.json b/manifest.json index 5d7a117..454d67e 100644 --- a/manifest.json +++ b/manifest.json @@ -1 +1 @@ -{"schema_version":"1.0","product":"ELUNVERA","generated_at":"2026-09-30T20:31:30Z","algorithm":"SHA-256","self_excluded":true,"file_count":58,"files":[{"path":".coderabbit.yaml","sha256":"efe46b993fae145eeaa2b2fb2cf0c302000c6373e5246c8e54bf330d636f4e2b","size_bytes":112,"line_count":7},{"path":".cwl/data-management.yaml","sha256":"28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671","size_bytes":1727,"line_count":48},{"path":".github/pull_request_template.md","sha256":"d7584adf5eb9866449fc5f38dc490422bf23de31ae75e1bdb385265c68122d15","size_bytes":1064,"line_count":38},{"path":".github/workflows/document-contracts.yml","sha256":"a28db289bf927a8eaf441bb89ccc49e7146c98bea6e025a6ffbb1c8fb70ea8be","size_bytes":11008,"line_count":225},{"path":"AGENTS.md","sha256":"6c97e76c8ec1da4d30b82a1759755bae11018c132ca0fd29d7dfc803b55006a1","size_bytes":4152,"line_count":84},{"path":"CHANGELOG.md","sha256":"48d234ba74a97edc4d899db91b13dead2baac8ad3354212f4a756eadcb95ef20","size_bytes":3991,"line_count":44},{"path":"CLAUDE.md","sha256":"67f513ae368f851201f50b6f732f444a648b3a940ca261411edbbc4c9f1ab223","size_bytes":1684,"line_count":34},{"path":"CONTRIBUTING.md","sha256":"5aee2d583ac082626a59cca4a832715ab6c9ef0e406ae48c7976887c71a74127","size_bytes":1696,"line_count":43},{"path":"LICENSE","sha256":"b7fa79459ac09645fd5bed5363852ba8759fa6deeb972d02f09fb0dc50fef586","size_bytes":11290,"line_count":192},{"path":"README.md","sha256":"3c65f74b492dfe6ae8e06eedd23a5ffde397d06b751d10a29f464c0621b77b04","size_bytes":5471,"line_count":84},{"path":"SECURITY.md","sha256":"4bfbb000844294b22ff9882211ee0a57b38e637002847cfdde8818b9276851eb","size_bytes":1091,"line_count":32},{"path":"docs/API_CONTRACT.md","sha256":"8140d7fdad34c28767892a4e5920d3ad42d3f429f0cf0fa07a0c4f219911d4a8","size_bytes":9174,"line_count":228},{"path":"docs/ARCHITECTURE.md","sha256":"f4e39936636d48ed0d4d1c21f02562860be1af19fe8eec2d75e1d9049c30861f","size_bytes":9402,"line_count":250},{"path":"docs/DATA_MODEL.md","sha256":"3bbfe050809c960406514ff3ad0d8a273dc84b80c377189fd23f2c80f40da10a","size_bytes":15101,"line_count":504},{"path":"docs/OPERABILITY.md","sha256":"1c725823885df063bb43d8d9e4d80258ed6b9ef5029bb97cdf5100f7ec7dc80d","size_bytes":7003,"line_count":151},{"path":"docs/PRD.md","sha256":"fa61eb2cfda4013ef6d2d083b1e2ea21a307f77768e689ea5eb8f24987a6c15f","size_bytes":23521,"line_count":369},{"path":"docs/PRIVACY.md","sha256":"0599406e743af7c561208da8ad505c704ea585cebeb941444d221584aad5e004","size_bytes":6899,"line_count":141},{"path":"docs/ROADMAP.md","sha256":"3e94efa42e1553428dd90c8bd6b298b114a1af8188faa0968f690b6dd4f9a486","size_bytes":3415,"line_count":84},{"path":"docs/SECURITY.md","sha256":"d10ae9757a7233b9ce73eaa038f75939d22da4709ac6db7ee16fe4b291bd64dd","size_bytes":8100,"line_count":174},{"path":"docs/STORYBOARD.md","sha256":"c9e2d38ca25e024a7599afeff711187be272cebc7c51a9ca603846bf33bda392","size_bytes":2775,"line_count":41},{"path":"docs/STORYBOOK_INVENTORY.md","sha256":"e210ed7072720bef3b825f226419ff25dd68ee412d5272f0e5d51234b8ea4fe1","size_bytes":2354,"line_count":99},{"path":"docs/TEST_STRATEGY.md","sha256":"b1240c75308ea22db6f4c7d2e2f7ac16d11497c5d551f3c994113d6ac67f6a17","size_bytes":9456,"line_count":178},{"path":"docs/THREAT_MODEL.md","sha256":"1dc10db1d5fb0a314e25cd78c9bb1ed90b40315dbb3a32d387c2b5758910100f","size_bytes":7043,"line_count":132},{"path":"docs/TRD.md","sha256":"fa1e830ba1eecf773ea265e3d2ae620af5ab15d00f8d9ea53d8f511322934c5a","size_bytes":17622,"line_count":359},{"path":"docs/UML.md","sha256":"882a33a38bda7494e370f4135b9a3d7c5d3cf054d47cc511f3813eb046916d0c","size_bytes":3165,"line_count":115},{"path":"docs/USER_STORIES.md","sha256":"cdc8e1a2b74d7821279dfe0f07dda2d25b9bae088a720b9a6fb19270af36208c","size_bytes":3184,"line_count":37},{"path":"docs/USE_CASES.md","sha256":"4df536423c1796793edd35c200b624e6ec1daa87adf6ace9748608f24c254022","size_bytes":4357,"line_count":69},{"path":"docs/UX_SPEC.md","sha256":"e57641260cbb7ca177c773478699e03dca06b4bce3e4f994f0476187881e2919","size_bytes":8021,"line_count":178},{"path":"docs/VALIDATION_REPORT.md","sha256":"2e9d563bb02dea4a8c62b7f8c0c1fca22457ae6304bcd8d2436caeb96321a49d","size_bytes":3071,"line_count":59},{"path":"docs/WIREFRAMES.md","sha256":"e989815acd882701ff2737036ae6f278b5a01c45081204c3c65c33c9dc0e4f01","size_bytes":4526,"line_count":81},{"path":"docs/adr/0001-product-boundary.md","sha256":"86f3513bdfa2c2c8766c6c2afdbec7b099778982e9246efe729b5d9f76da3e24","size_bytes":1151,"line_count":21},{"path":"docs/adr/0002-modular-monolith.md","sha256":"0415bc80db206f5581c758a83f09abe14bfa5e45e76fbc2b38b7bb958d2342bb","size_bytes":955,"line_count":21},{"path":"docs/adr/0003-keyverse-identity.md","sha256":"10fccb512eff2665cf0b43ef5bbef1cdf4501962e0ae353777f131a75552c309","size_bytes":865,"line_count":21},{"path":"docs/adr/0004-bitemporal-truth.md","sha256":"d7d85c1fefeed397e417653a46e1ddd2d9505740f9369d2f16769dac344d373c","size_bytes":875,"line_count":21},{"path":"docs/adr/0005-first-class-relationships.md","sha256":"1130b14f9f448d3aba40086cb1355683c0d5b4891368706c860b41e5467a5852","size_bytes":848,"line_count":21},{"path":"docs/adr/0006-provider-neutral-integrations.md","sha256":"318a12fb63ed4c788af86aa45ff1c95430f6f199bf012c1f966b073be469e7a9","size_bytes":861,"line_count":21},{"path":"docs/adr/0007-purpose-aware-privacy.md","sha256":"9ce6767604ee5787e0e2b4f051272cb7a2288be4dc8ba06e1b7bd3ffe54b0664","size_bytes":944,"line_count":21},{"path":"docs/adr/0008-ai-human-judgment.md","sha256":"1d2d14e8b6b0a03a18180a6e1a7efe9b2212afda74bd250c1c8745e5f700706d","size_bytes":950,"line_count":21},{"path":"docs/adr/0009-postgresql-system-of-record.md","sha256":"9ca96bc56d1658c933f89e3fe34b24cf0707e1b2e4862bc4929c8f4889b36bf7","size_bytes":862,"line_count":21},{"path":"docs/adr/0010-rust-compute-boundary.md","sha256":"b9e7d8f0da93a8c5f8dec5892d097c2eaab7eb4057b1a0f7a510ff22f29a5ccf","size_bytes":979,"line_count":21},{"path":"docs/adr/0011-contract-versioning.md","sha256":"76381bc76cfd59fd2a4bbd8831c217f1e6ca2625079d5c59b90d09fadc5f8afb","size_bytes":877,"line_count":21},{"path":"docs/adr/0012-quality-release-gates.md","sha256":"7083f64c1d394ad57cb8a1f19a9728b39dc032f59c6c159dabf2603751625144","size_bytes":945,"line_count":21},{"path":"docs/adr/0013-brand-and-license.md","sha256":"e27ab7029b52981abab21aacb1ed5fec8e458e1ff40163c4ab504c5426544b86","size_bytes":3160,"line_count":32},{"path":"docs/adr/0014-ux-design-system.md","sha256":"3121dfd4944a529a526a1ff3809d5c83a35360136973672f01a5d262f9a3d50a","size_bytes":977,"line_count":21},{"path":"docs/adr/0015-retention-disposition.md","sha256":"2b6b3fc4e3ddad2564e7bd9819d4aa4f980e3befb12d947ede25987a041e654c","size_bytes":915,"line_count":21},{"path":"docs/adr/0016-cwl-ecosystem-boundaries.md","sha256":"fb59ab82e8a9c5e19702412e25e22318587fd155a4dd41b14de6497b1de8066d","size_bytes":964,"line_count":21},{"path":"docs/adr/README.md","sha256":"ebd75a0c60d4dd3bd13f3135b3c81732013d8ace8ccc263b9ca7703fa406f5aa","size_bytes":1818,"line_count":22},{"path":"docs/doctoring/REFERENCES.md","sha256":"3508c3d2c9a886cb1e6fa5ed90a380e22feac730dcde737c953b1e1e04d3d5fb","size_bytes":4519,"line_count":59},{"path":"docs/doctoring/RESEARCH_BASIS.md","sha256":"1ecf6adb21fc6cfbf355fb61256c93fb20028ae228b8c910d97a867d73f184a4","size_bytes":2221,"line_count":29},{"path":"docs/doctoring/STANDARD_TRACEABILITY.md","sha256":"38d44ddfab32c0a7bf2bb7935bded795dd0a84800427e5518d64ff6a261f2314","size_bytes":2560,"line_count":22},{"path":"docs/index.md","sha256":"d7641f7c026b0bba9c7c8539b68c729517aade17de6af3656c5bf2942fded9a3","size_bytes":4611,"line_count":49},{"path":"docs/product-technical-gap-baseline.md","sha256":"7327cc5d017bd5c7f015f652f4090ad24b70495235f4f934c7bd67e375a88b55","size_bytes":16581,"line_count":248},{"path":"docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md","sha256":"d453a94d4b5d2650aff49619da9733d057c5df80b241fe6a43ee0d95db99ebed","size_bytes":16116,"line_count":433},{"path":"docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md","sha256":"45debe0ac12d4648d21c0a8fb53fb9b30b07188a6b8e3ce0c9e4e22ebc34d999","size_bytes":4509,"line_count":67},{"path":"schemas/asyncapi.yaml","sha256":"b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c","size_bytes":3682,"line_count":126},{"path":"schemas/events/opportunity-stage-changed-v1.schema.json","sha256":"03c3ac79ffe93f518255401c12cc809eda31b4b5623bdc81474f44dcc8bf28b8","size_bytes":1486,"line_count":63},{"path":"schemas/events/relationship-changed-v1.schema.json","sha256":"bfcb12a02e472b74a20152a5671f5ebf18d80389a8bbe466e289873645a4945f","size_bytes":1545,"line_count":72},{"path":"schemas/openapi.yaml","sha256":"795ad75441d033a0f80dfe5a054328110858886929d10a02dc1c36dee5039781","size_bytes":13265,"line_count":504}]} +{"schema_version":"1.0","product":"ELUNVERA","generated_at":"2026-09-30T21:14:59Z","algorithm":"SHA-256","self_excluded":true,"file_count":58,"files":[{"path":".coderabbit.yaml","sha256":"efe46b993fae145eeaa2b2fb2cf0c302000c6373e5246c8e54bf330d636f4e2b","size_bytes":112,"line_count":7},{"path":".cwl/data-management.yaml","sha256":"28a06ccaf397a9da80f49ca09742a8cd18091c96c0ecb0f463192dfcea895671","size_bytes":1727,"line_count":48},{"path":".github/pull_request_template.md","sha256":"d7584adf5eb9866449fc5f38dc490422bf23de31ae75e1bdb385265c68122d15","size_bytes":1064,"line_count":38},{"path":".github/workflows/document-contracts.yml","sha256":"bf9417feae4168d8488bd95a7010ef3f0778133ea458277603441a8b1796f3e8","size_bytes":12999,"line_count":262},{"path":"AGENTS.md","sha256":"6c97e76c8ec1da4d30b82a1759755bae11018c132ca0fd29d7dfc803b55006a1","size_bytes":4152,"line_count":84},{"path":"CHANGELOG.md","sha256":"48d234ba74a97edc4d899db91b13dead2baac8ad3354212f4a756eadcb95ef20","size_bytes":3991,"line_count":44},{"path":"CLAUDE.md","sha256":"67f513ae368f851201f50b6f732f444a648b3a940ca261411edbbc4c9f1ab223","size_bytes":1684,"line_count":34},{"path":"CONTRIBUTING.md","sha256":"5aee2d583ac082626a59cca4a832715ab6c9ef0e406ae48c7976887c71a74127","size_bytes":1696,"line_count":43},{"path":"LICENSE","sha256":"b7fa79459ac09645fd5bed5363852ba8759fa6deeb972d02f09fb0dc50fef586","size_bytes":11290,"line_count":192},{"path":"README.md","sha256":"3c65f74b492dfe6ae8e06eedd23a5ffde397d06b751d10a29f464c0621b77b04","size_bytes":5471,"line_count":84},{"path":"SECURITY.md","sha256":"4bfbb000844294b22ff9882211ee0a57b38e637002847cfdde8818b9276851eb","size_bytes":1091,"line_count":32},{"path":"docs/API_CONTRACT.md","sha256":"8140d7fdad34c28767892a4e5920d3ad42d3f429f0cf0fa07a0c4f219911d4a8","size_bytes":9174,"line_count":228},{"path":"docs/ARCHITECTURE.md","sha256":"f4e39936636d48ed0d4d1c21f02562860be1af19fe8eec2d75e1d9049c30861f","size_bytes":9402,"line_count":250},{"path":"docs/DATA_MODEL.md","sha256":"da5b3a6e7073655849f000a7d398078c650b5552ad142321fc423d7e269e700d","size_bytes":15174,"line_count":504},{"path":"docs/OPERABILITY.md","sha256":"1c725823885df063bb43d8d9e4d80258ed6b9ef5029bb97cdf5100f7ec7dc80d","size_bytes":7003,"line_count":151},{"path":"docs/PRD.md","sha256":"fa61eb2cfda4013ef6d2d083b1e2ea21a307f77768e689ea5eb8f24987a6c15f","size_bytes":23521,"line_count":369},{"path":"docs/PRIVACY.md","sha256":"0599406e743af7c561208da8ad505c704ea585cebeb941444d221584aad5e004","size_bytes":6899,"line_count":141},{"path":"docs/ROADMAP.md","sha256":"3e94efa42e1553428dd90c8bd6b298b114a1af8188faa0968f690b6dd4f9a486","size_bytes":3415,"line_count":84},{"path":"docs/SECURITY.md","sha256":"d10ae9757a7233b9ce73eaa038f75939d22da4709ac6db7ee16fe4b291bd64dd","size_bytes":8100,"line_count":174},{"path":"docs/STORYBOARD.md","sha256":"c9e2d38ca25e024a7599afeff711187be272cebc7c51a9ca603846bf33bda392","size_bytes":2775,"line_count":41},{"path":"docs/STORYBOOK_INVENTORY.md","sha256":"81a86ea272d011d8994bc1f794bc3942675630049ee8950010740a4472e947ec","size_bytes":2404,"line_count":105},{"path":"docs/TEST_STRATEGY.md","sha256":"b1240c75308ea22db6f4c7d2e2f7ac16d11497c5d551f3c994113d6ac67f6a17","size_bytes":9456,"line_count":178},{"path":"docs/THREAT_MODEL.md","sha256":"1dc10db1d5fb0a314e25cd78c9bb1ed90b40315dbb3a32d387c2b5758910100f","size_bytes":7043,"line_count":132},{"path":"docs/TRD.md","sha256":"fa1e830ba1eecf773ea265e3d2ae620af5ab15d00f8d9ea53d8f511322934c5a","size_bytes":17622,"line_count":359},{"path":"docs/UML.md","sha256":"2faf533b8f87092151ff878539192570d48b7e79a3bc1b24027e2e95a05c8b08","size_bytes":3375,"line_count":122},{"path":"docs/USER_STORIES.md","sha256":"cdc8e1a2b74d7821279dfe0f07dda2d25b9bae088a720b9a6fb19270af36208c","size_bytes":3184,"line_count":37},{"path":"docs/USE_CASES.md","sha256":"4df536423c1796793edd35c200b624e6ec1daa87adf6ace9748608f24c254022","size_bytes":4357,"line_count":69},{"path":"docs/UX_SPEC.md","sha256":"e57641260cbb7ca177c773478699e03dca06b4bce3e4f994f0476187881e2919","size_bytes":8021,"line_count":178},{"path":"docs/VALIDATION_REPORT.md","sha256":"2e9d563bb02dea4a8c62b7f8c0c1fca22457ae6304bcd8d2436caeb96321a49d","size_bytes":3071,"line_count":59},{"path":"docs/WIREFRAMES.md","sha256":"e989815acd882701ff2737036ae6f278b5a01c45081204c3c65c33c9dc0e4f01","size_bytes":4526,"line_count":81},{"path":"docs/adr/0001-product-boundary.md","sha256":"86f3513bdfa2c2c8766c6c2afdbec7b099778982e9246efe729b5d9f76da3e24","size_bytes":1151,"line_count":21},{"path":"docs/adr/0002-modular-monolith.md","sha256":"0415bc80db206f5581c758a83f09abe14bfa5e45e76fbc2b38b7bb958d2342bb","size_bytes":955,"line_count":21},{"path":"docs/adr/0003-keyverse-identity.md","sha256":"10fccb512eff2665cf0b43ef5bbef1cdf4501962e0ae353777f131a75552c309","size_bytes":865,"line_count":21},{"path":"docs/adr/0004-bitemporal-truth.md","sha256":"d7d85c1fefeed397e417653a46e1ddd2d9505740f9369d2f16769dac344d373c","size_bytes":875,"line_count":21},{"path":"docs/adr/0005-first-class-relationships.md","sha256":"1130b14f9f448d3aba40086cb1355683c0d5b4891368706c860b41e5467a5852","size_bytes":848,"line_count":21},{"path":"docs/adr/0006-provider-neutral-integrations.md","sha256":"318a12fb63ed4c788af86aa45ff1c95430f6f199bf012c1f966b073be469e7a9","size_bytes":861,"line_count":21},{"path":"docs/adr/0007-purpose-aware-privacy.md","sha256":"9ce6767604ee5787e0e2b4f051272cb7a2288be4dc8ba06e1b7bd3ffe54b0664","size_bytes":944,"line_count":21},{"path":"docs/adr/0008-ai-human-judgment.md","sha256":"1d2d14e8b6b0a03a18180a6e1a7efe9b2212afda74bd250c1c8745e5f700706d","size_bytes":950,"line_count":21},{"path":"docs/adr/0009-postgresql-system-of-record.md","sha256":"9ca96bc56d1658c933f89e3fe34b24cf0707e1b2e4862bc4929c8f4889b36bf7","size_bytes":862,"line_count":21},{"path":"docs/adr/0010-rust-compute-boundary.md","sha256":"b9e7d8f0da93a8c5f8dec5892d097c2eaab7eb4057b1a0f7a510ff22f29a5ccf","size_bytes":979,"line_count":21},{"path":"docs/adr/0011-contract-versioning.md","sha256":"76381bc76cfd59fd2a4bbd8831c217f1e6ca2625079d5c59b90d09fadc5f8afb","size_bytes":877,"line_count":21},{"path":"docs/adr/0012-quality-release-gates.md","sha256":"7083f64c1d394ad57cb8a1f19a9728b39dc032f59c6c159dabf2603751625144","size_bytes":945,"line_count":21},{"path":"docs/adr/0013-brand-and-license.md","sha256":"e27ab7029b52981abab21aacb1ed5fec8e458e1ff40163c4ab504c5426544b86","size_bytes":3160,"line_count":32},{"path":"docs/adr/0014-ux-design-system.md","sha256":"3121dfd4944a529a526a1ff3809d5c83a35360136973672f01a5d262f9a3d50a","size_bytes":977,"line_count":21},{"path":"docs/adr/0015-retention-disposition.md","sha256":"2b6b3fc4e3ddad2564e7bd9819d4aa4f980e3befb12d947ede25987a041e654c","size_bytes":915,"line_count":21},{"path":"docs/adr/0016-cwl-ecosystem-boundaries.md","sha256":"fb59ab82e8a9c5e19702412e25e22318587fd155a4dd41b14de6497b1de8066d","size_bytes":964,"line_count":21},{"path":"docs/adr/README.md","sha256":"ebd75a0c60d4dd3bd13f3135b3c81732013d8ace8ccc263b9ca7703fa406f5aa","size_bytes":1818,"line_count":22},{"path":"docs/doctoring/REFERENCES.md","sha256":"3508c3d2c9a886cb1e6fa5ed90a380e22feac730dcde737c953b1e1e04d3d5fb","size_bytes":4519,"line_count":59},{"path":"docs/doctoring/RESEARCH_BASIS.md","sha256":"1ecf6adb21fc6cfbf355fb61256c93fb20028ae228b8c910d97a867d73f184a4","size_bytes":2221,"line_count":29},{"path":"docs/doctoring/STANDARD_TRACEABILITY.md","sha256":"38d44ddfab32c0a7bf2bb7935bded795dd0a84800427e5518d64ff6a261f2314","size_bytes":2560,"line_count":22},{"path":"docs/index.md","sha256":"d7641f7c026b0bba9c7c8539b68c729517aade17de6af3656c5bf2942fded9a3","size_bytes":4611,"line_count":49},{"path":"docs/product-technical-gap-baseline.md","sha256":"7327cc5d017bd5c7f015f652f4090ad24b70495235f4f934c7bd67e375a88b55","size_bytes":16581,"line_count":248},{"path":"docs/superpowers/plans/2026-08-27-elunvera-foundation-implementation-plan.md","sha256":"ee659ab364054348c7ce96b3f3a63e0c127e92606fc6c6ac35255d302e92bd39","size_bytes":17542,"line_count":441},{"path":"docs/superpowers/specs/2026-08-27-elunvera-product-technical-baseline-design.md","sha256":"45debe0ac12d4648d21c0a8fb53fb9b30b07188a6b8e3ce0c9e4e22ebc34d999","size_bytes":4509,"line_count":67},{"path":"schemas/asyncapi.yaml","sha256":"b973b10d1db3c003df97bcc0d25676bdccfa1238c04f70188e8f54cc9a117a4c","size_bytes":3682,"line_count":126},{"path":"schemas/events/opportunity-stage-changed-v1.schema.json","sha256":"03c3ac79ffe93f518255401c12cc809eda31b4b5623bdc81474f44dcc8bf28b8","size_bytes":1486,"line_count":63},{"path":"schemas/events/relationship-changed-v1.schema.json","sha256":"bfcb12a02e472b74a20152a5671f5ebf18d80389a8bbe466e289873645a4945f","size_bytes":1545,"line_count":72},{"path":"schemas/openapi.yaml","sha256":"d8dbcfae1be18310ef562b7283816607519837e69c271b8ad9e64105b3810f34","size_bytes":13289,"line_count":505}]} diff --git a/schemas/openapi.yaml b/schemas/openapi.yaml index 77cf8c9..5b3c2aa 100644 --- a/schemas/openapi.yaml +++ b/schemas/openapi.yaml @@ -296,6 +296,7 @@ components: properties: items: type: array + maxItems: 100 items: $ref: '#/components/schemas/Account' next_cursor: