Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 9 additions & 40 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ concurrency:
cancel-in-progress: true

jobs:
validate-and-build:
quality-checks:
runs-on: ubuntu-latest
steps:
- name: Checkout
Expand All @@ -30,52 +30,21 @@ jobs:
sudo apt-get update
sudo apt-get install -y graphviz

- name: Install Python deps
- name: Install package
run: |
python -m pip install --upgrade pip
pip install rdflib pyshacl graphviz pydot
pip install .[dev]

- name: Validate SHACL
- name: Validate SHACL on sample data
run: |
python tools/validate_shapes.py
python -m goblin.validate --data samples/goblin-sample.ttl

- name: Export TTL graph to DOT/SVG/PNG
- name: Lint DOT (render to SVG)
run: |
python tools/export_instances_dot.py
dot -Tsvg goblin-map.dot -o /tmp/goblin-map.svg

- name: Export web JSON
- name: Verify WebVOWL availability
run: |
python tools/export_web_json.py

- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: "20"

- name: Build web (TS -> docs)
working-directory: web
run: |
npm ci
npm run build

- name: Upload artifact (docs)
uses: actions/upload-pages-artifact@v3
with:
path: docs

deploy:
needs: validate-and-build
if: github.ref == 'refs/heads/main'
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
curl -I --fail https://service.tib.eu/webvowl/


41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,14 @@ This bundle contains:
- `goblin-map.dot` — Graphviz DOT file for a "Goblin map" of common domains.
- `goblin-agent-lim42.md` — lim42-ready agent spec for computing Goblin scores.
- `goblin-energy-gradient.md` — energy gradient interpretation with simple flow equations.
- Rendered `docs/goblin-map.svg` — quick visual of the Goblin map without requiring Graphviz (generate PNG locally with `dot -Tpng goblin-map.dot -o docs/goblin-map.png` if you prefer).

You can `pip install .` (or `pip install -e .` for development) to get the ontology, SHACL shapes, and validation helpers as a tiny Python package (`goblin-score`).
Then validate data against the bundled shapes (after installation):

```bash
python -m goblin.validate --data samples/goblin-sample.ttl
```

## Meme / Usage

Expand All @@ -29,4 +37,35 @@ The Goblin score is defined in the ontology as `ui:goblinScore` and is an alias

- Push this bundle into `nkllon/goblin` as initial commit.
- Wire `goblin-agent-lim42.md` into lim42 as a reusable agent profile.
- Render `goblin-map.dot` with Graphviz to produce a PNG/SVG for documentation.
- Render `goblin-map.dot` with Graphviz to produce a PNG/SVG for documentation. ✅

## Scoring workflow (lim42 example)

Use the existing lim42 agent prompt (`goblin-agent-lim42.md`) and weights to go from a system description to a JSON score.

**Example prompt input** (shortened):

> "A multi-tenant SaaS with asynchronous provisioning, eventual consistency across regions, and teams expecting deterministic dashboards. Observability is partial; on-call engineers rely on retries and manual overrides."

**Expected JSON output shape** (weights baked into the agent):

```json
{
"goblin_score": 0.82,
"dimensions": {
"illusion_closure": 0.90,
"distributed_state": 0.85,
"async_nondeterminism": 0.80,
"stakeholder_demand_for_determinism": 0.70,
"observability_deficit": 0.60,
"energy_gradient_misalignment": 0.95
},
"commentary": "Async provisioning and partial observability create large closure illusions; teams expect deterministic dashboards."
}
```

## Goblin map preview

- [SVG](docs/goblin-map.svg) — scalable version from the DOT source (`goblin-map.dot`).
- To produce a PNG locally (not checked into the repo), run `dot -Tpng goblin-map.dot -o docs/goblin-map.png`.

126 changes: 126 additions & 0 deletions docs/goblin-map.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions docs/kg.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<a href="../goblin-ontology.ttl">goblin-ontology.ttl</a> ·
<a href="../goblin-shapes.ttl">goblin-shapes.ttl</a>
<span style="margin-left:10px;color:#666;">Use the embedded WebVOWL app and load the TTL via its UI.</span>
<span style="margin-left:10px;"><a href="goblin-map.svg">Goblin map (SVG)</a></span>
</header>
<iframe src="https://service.tib.eu/webvowl/" title="WebVOWL"></iframe>
</body>
Expand Down
25 changes: 25 additions & 0 deletions goblin-energy-gradient.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,3 +90,28 @@ In practice:
are high-leverage moves when their \( w_i \) are large.

Goblin score gives you a way to **prioritize** where to push on the system to reduce long-term misalignment energy.

## Numeric scenarios

Using the default weight assignment (`ui:DefaultWeights`):

- \( w_{\text{illusion}} = 0.18\)
- \( w_{\text{distributed}} = 0.20\)
- \( w_{\text{async}} = 0.15\)
- \( w_{\text{stakeholder}} = 0.10\)
- \( w_{\text{observability}} = 0.12\)
- \( w_{\text{energy-misalignment}} = 0.25\)

### Scenario A: Partial observability fix

Before: \( x = (0.90, 0.85, 0.80, 0.70, 0.60, 0.95) \) ⇒ \( G = 0.83 \)

After improving observability, moderating stakeholder expectations, and burning down the energy misalignment: \( x = (0.90, 0.85, 0.80, 0.55, 0.25, 0.55) \) ⇒ \( G = 0.67 \).

Because \( w_{\text{observability}} + w_{\text{stakeholder}} + w_{\text{energy-misalignment}} = 0.57 \), dropping those three dimensions by ~0.25 each cuts the Goblin score by ~0.16 and the energy \( E = kG \) by the same proportion.

### Scenario B: Chasing determinism without observability

Teams invest in automation that lowers async issues but ignore observability: \( x = (0.90, 0.80, 0.55, 0.65, 0.70, 0.95) \) ⇒ \( G = 0.79 \).

Even with \( x_{\text{async}} \) reduced by 0.25, the higher observability deficit pushes the score back up, illustrating a local vs. global gradient clash. SHACL shapes (`uiSh:ScoreComponentShape`, `uiSh:GoblinScoreShape`) keep each component in \([0,1]\) so these numeric moves remain valid instances.
33 changes: 33 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "goblin-score"
version = "0.1.0"
description = "Ontology, SHACL shapes, and helpers for the Goblin (SCIG) score"
authors = [{ name = "nkllon" }]
readme = "README.md"
requires-python = ">=3.9"
license = { text = "MIT" }
dependencies = [
"rdflib>=6.3",
"pyshacl>=0.26",
]

[project.optional-dependencies]
dev = [
"graphviz",
]

[project.scripts]
goblin-validate = "goblin.validate:main"

[tool.hatch.build.targets.wheel]
packages = ["src/goblin"]

[tool.hatch.build.targets.wheel.force-include]
"goblin-ontology.ttl" = "goblin/data/goblin-ontology.ttl"
"goblin-shapes.ttl" = "goblin/data/goblin-shapes.ttl"
"goblin-map.dot" = "goblin/data/goblin-map.dot"
"samples/goblin-sample.ttl" = "goblin/data/goblin-sample.ttl"
34 changes: 34 additions & 0 deletions samples/goblin-sample.ttl
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
@prefix ui: <https://nkllon.com/ui#> .
@prefix ex: <https://example.com/goblin#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .

# Minimal sample that exercises Goblin score components and shape validation.
ex:CheckoutWorkflow a ui:ProblemClass ;
ui:goblinScore "0.82"^^xsd:decimal ;
ui:hasTier ui:High ;
ui:hasScoreComponent ex:ScoreIllusion , ex:ScoreDistributed , ex:ScoreAsync , ex:ScoreObservability , ex:ScoreEnergy , ex:ScoreStakeholder ;
ui:hasWeighting ui:DefaultWeights .

ex:ScoreIllusion a ui:ScoreComponent ;
ui:forDimension ui:Dim1_IllusionClosure ;
ui:componentValue "0.90"^^xsd:decimal .

ex:ScoreDistributed a ui:ScoreComponent ;
ui:forDimension ui:Dim2_DistributedState ;
ui:componentValue "0.85"^^xsd:decimal .

ex:ScoreAsync a ui:ScoreComponent ;
ui:forDimension ui:Dim3_AsyncNonDeterminism ;
ui:componentValue "0.80"^^xsd:decimal .

ex:ScoreStakeholder a ui:ScoreComponent ;
ui:forDimension ui:Dim4_DomainInvariants ;
ui:componentValue "0.70"^^xsd:decimal .

ex:ScoreObservability a ui:ScoreComponent ;
ui:forDimension ui:Dim5_SecurityPrivacy ;
ui:componentValue "0.60"^^xsd:decimal .

ex:ScoreEnergy a ui:ScoreComponent ;
ui:forDimension ui:Dim22_EnergyGradientSensitivity ;
ui:componentValue "0.95"^^xsd:decimal .
8 changes: 8 additions & 0 deletions src/goblin/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Goblin (SCIG) ontology helper package."""

from .resources import available_resources, resource_stream

__all__ = [
"available_resources",
"resource_stream",
]
1 change: 1 addition & 0 deletions src/goblin/data/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Packaged data files for Goblin (ontology, SHACL shapes, and map)."""
1 change: 1 addition & 0 deletions src/goblin/data/goblin-map.dot
1 change: 1 addition & 0 deletions src/goblin/data/goblin-ontology.ttl
1 change: 1 addition & 0 deletions src/goblin/data/goblin-sample.ttl
1 change: 1 addition & 0 deletions src/goblin/data/goblin-shapes.ttl
Loading