Compare commits

...

27 Commits

Author SHA1 Message Date
cbfb3d0f74 Draft capability entry (reuse-surface REUSE-WP-0017-T04, cohort 3)
Honest first-pass maturity vector grounded in README/docs/tests present
in this repo; no invented evidence. Flagged for human review before
publish. See reuse-surface history/2026-07-06-coverage-classification.md.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-06 19:50:53 +02:00
20316c533f Recorded decision 2026-07-04 00:31:34 +02:00
58a2cfac5c Regenerate agent instructions: workstream -> workplan terminology
Registration guidance now prescribes file-first + fix-consistency (C-06)
instead of manual create_workplan/create_workstream calls; progress-event
examples use workplan_id; legacy field names annotated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 01:47:46 +02:00
7312ed3767 Archive closed workplans to workplans/archived/ (ADR-001)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 00:25:41 +02:00
f9e661ec69 chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-07-02:
  - update .custodian-brief.md for railiance-fabric
2026-07-02 00:24:01 +02:00
f57a5c1dce Repo hygiene: fill stack-and-commands, normalize workplan statuses
- Fill .claude/rules/stack-and-commands.md (was an empty TODO template)
- Normalize workplan frontmatter statuses to canonical vocabulary
  (completed/done -> finished) per ADR-001

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-02 00:21:49 +02:00
757770b42f Record whynot-design publish lane decisions 2026-07-01 20:07:20 +02:00
635521406f Normalize agent instructions and workplan frontmatter (STATE-WP-0067)
- Align agent files with on-disk workplan prefixes (infer from workplan ids)
- Set workplan domain to registered domain_slug; add topic_slug where applicable
- Repair frontmatter delimiter formatting; migrate legacy task status literals
- Regenerate AGENTS.md, CLAUDE.md, and .claude/rules from State Hub templates
2026-06-22 23:16:28 +02:00
2afeb86ed2 Add .repo-classification.yaml (CUST-WP-0050 T11 agent first-pass) 2026-06-22 17:47:41 +02:00
caa1e4100d Add credential routing instructions for all agent runtimes
Propagate shared credential-routing section (Codex, Claude, Grok, llm-connect)
from state-hub template via scripts/propagate_credential_routing.py.
2026-06-18 22:48:39 +02:00
dae9e3409a Add capability registry index scaffold (REUSE-WP-0014-T07 B05) 2026-06-16 01:59:28 +02:00
e23ed0c06b Document semantic attractors concept 2026-06-06 00:52:21 +02:00
fe2e98e2a4 Track generated State Hub decision log 2026-06-05 22:23:38 +02:00
7cb943ed41 Finish zone drag verification workplan 2026-06-05 21:38:03 +02:00
31841d0f1c chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-06-05:
  - update .custodian-brief.md for railiance-fabric
2026-06-05 21:36:10 +02:00
40b409cd92 Sync fabric workplan IDs 2026-06-05 17:12:48 +02:00
0b5d295800 Declare forge graph contracts 2026-06-05 17:10:31 +02:00
5dff7f14da chore(consistency): sync task status from DB [auto]
Updated by fix-consistency on 2026-06-05:
  - update .custodian-brief.md for railiance-fabric
2026-06-05 17:07:16 +02:00
5e89f6a075 chore: add graph explorer make target 2026-06-03 17:24:58 +02:00
f09f110e77 feat: add zone layout selector 2026-05-25 03:17:23 +02:00
558e0dc157 feat: stabilize graph zone containers 2026-05-25 02:08:45 +02:00
0f7b7d1fed feat: add draggable graph zones 2026-05-25 01:09:05 +02:00
9b612447ca docs: finish zone entity workplan 2026-05-25 00:43:34 +02:00
a7a22a673f feat: prototype graph zone collapse 2026-05-25 00:40:13 +02:00
296ac051a7 feat: persist graph explorer zone state 2026-05-25 00:27:10 +02:00
1ad432270b feat: show zone resolver diagnostics 2026-05-25 00:09:18 +02:00
f1cd74dc7b feat: resolve graph explorer zones from definitions 2026-05-25 00:00:28 +02:00
87 changed files with 3442 additions and 186 deletions

View File

@@ -0,0 +1,50 @@
# Credential and access routing
**Audience:** Codex, Claude Code, Grok, and custodian agents that call **llm-connect**
for inference. Run this check **before** requesting secrets, API keys, SSH access,
login tokens, or database passwords — in any repo, not only `ops-warden`.
ops-warden **issues SSH certificates only** (`warden sign`, `cert_command`). Every
other credential need belongs to another subsystem. **Do not** message
`ops-warden` on State Hub expecting a secret value; the reply is a pointer, not a key.
### Lookup (do this first)
```bash
warden route find "<describe your need>" --json
warden route show <catalog-id> --json
```
Requires the `warden` CLI from `~/ops-warden` (`uv tool install .` or `uv run warden`).
| Agent runtime | How to orient |
| --- | --- |
| **Codex / Grok** (shell, HTTP State Hub) | `warden route` commands above; inbox `to_agent=railiance-fabric` is for coordination, not secret vending |
| **Claude Code** (MCP when available) | `get_domain_summary("custodian")` for workplans; **still** use `warden route` for credential ownership |
| **llm-connect** (inference service) | Never put secret retrieval in prompts; route custody to OpenBao/operator paths surfaced by `warden route` |
### Quick routing table
| I need… | Owner | ops-warden executes? |
| --- | --- | --- |
| SSH cert (`adm`/`agt`/`atm`) | ops-warden | **Yes**`warden sign` |
| API key, DB password, provider token | OpenBao (`railiance-platform`) | No — route only |
| Login / OIDC / MFA | key-cape / Keycloak | No — route only |
| Authorization decision | flex-auth | No — route only |
| activity-core → issue-core emission | activity-core + issue-core | No — `warden route show activity-core-issue-sink` |
| SSH tunnel | ops-bridge (+ `cert_command` from warden) | No — route only |
### Anti-patterns (do not do these)
- `POST /messages/` to `ops-warden` asking for `ISSUE_CORE_API_KEY`, `OPENROUTER_API_KEY`, etc.
- Inventing `warden secret`, `warden login`, `warden bao`, `warden tunnel` — they do not exist
- Pasting secrets into Git, State Hub, workplans, logs, or chat
### Other capabilities (reuse-surface)
Non-credential capabilities are usually discovered through **reuse-surface** federation
(`reuse-surface` registry / `capability.*` indexes). Credential routing is inlined in
every repo's agent instructions because it is high-frequency, high-risk, and easy to
get wrong.
**Canon:** `~/ops-warden/wiki/CredentialRouting.md` · catalog `~/ops-warden/registry/routing/catalog.yaml`

View File

@@ -1,37 +1,41 @@
## First Session Protocol
Triggered when `get_domain_summary("railiance")` shows **no workstreams**.
Triggered when `get_domain_summary("financials")` shows **no workplans**.
The project is registered but work has not yet been structured.
**Step 1 — Read, don't write**
- `~/the-custodian/canon/projects/railiance/project_charter_v0.1.md` — purpose, scope
- `~/the-custodian/canon/projects/railiance/roadmap_v0.1.md` — planned phases
- `~/the-custodian/canon/projects/financials/project_charter_v0.1.md` — purpose, scope
- `~/the-custodian/canon/projects/financials/roadmap_v0.1.md` — planned phases
- Scan repo root: README, directory structure, existing code or docs
**Step 2 — Survey in-progress work**
Look for TODOs, open branches, half-finished files. Note done vs. started but incomplete.
**Step 3 — Propose workstreams to Bernd**
Propose 13 workstreams — each a coherent strand, weeks to months, anchored to a
**Step 3 — Propose workplans to Bernd**
Propose 13 workplans — each a coherent strand, weeks to months, anchored to a
roadmap phase. **Wait for approval before creating.**
**Step 4 — Create workplan file first, then DB record (ADR-001)**
**Step 4 — Write the workplan file; fix-consistency registers it (ADR-001)**
```
workplans/railiance-fabric-WP-NNNN-<slug>.md ← write this first
workplans/RAILIANCE-WP-NNNN-<slug>.md ← write this, commit it
```
Then register in the hub:
```
create_workstream(topic_id="ca369340-a64e-442e-98f1-a4fa7dc74a38", title="...", owner="...", description="...")
create_task(workstream_id="<id>", title="...", priority="high|medium|low")
Then register by running the consistency check — do **not** call
`create_workplan`/`create_task` (or legacy `create_workstream`) yourself;
manual registration duplicates what C-06 creates from the file:
```bash
statehub fix-consistency --repo railiance-fabric
```
C-06 creates the hub workplan + tasks and writes `state_hub_workstream_id` /
`state_hub_task_id` back into the file (legacy field names, kept for
compatibility — they hold workplan/task IDs).
**Step 5 — Record the setup**
```
add_progress_event(
summary="First session: structured railiance into N workstreams, M tasks",
summary="First session: structured financials into N workplans, M tasks",
event_type="milestone",
topic_id="ca369340-a64e-442e-98f1-a4fa7dc74a38",
detail={"workstreams": [...], "tasks_created": M}
detail={"workplans": [...], "tasks_created": M}
)
```

View File

@@ -1,5 +1,5 @@
**Purpose:** railiance-fabric - (fill in purpose)
**Domain:** railiance
**Domain:** financials
**Repo slug:** railiance-fabric
**Topic ID:** ca369340-a64e-442e-98f1-a4fa7dc74a38

View File

@@ -1,6 +1,7 @@
## Session Protocol
State Hub: http://127.0.0.1:8000
Dev Hub (State Hub API): http://127.0.0.1:8000
MCP server name in `~/.claude.json`: `dev-hub`
**Step 1 — Orient**
@@ -10,7 +11,7 @@ cat .custodian-brief.md
```
Then call the MCP tool for richer cross-domain context when MCP tools are exposed:
```
get_domain_summary("railiance")
get_domain_summary("financials")
```
If MCP tools are unavailable in the current agent session, use the REST API:
```bash
@@ -39,11 +40,11 @@ curl -s -X PATCH "http://127.0.0.1:8000/messages/<id>/read" \
ls workplans/
```
For each file with `status: ready`, `active`, or `blocked`, note pending
`todo`/`in_progress` tasks.
`wait`/`todo`/`progress` tasks.
**Step 4 — Present brief**
1. **Active workstreams** for `railiance` — title, task counts, blocking decisions
1. **Active workplans** for `financials` — title, task counts, blocking decisions
2. **Pending tasks** from `workplans/` + any `[repo:railiance-fabric]` hub tasks
3. **Goal guidance** — if `goal_guidance` in summary:
- `needs_workplan`: surface as top action — *"Repo goal '{title}' has no workplan yet"*
@@ -51,33 +52,42 @@ For each file with `status: ready`, `active`, or `blocked`, note pending
4. **Suggested next action** — highest-priority open item
5. **SBOM status** — flag if `last_sbom_at` is unset for this repo
If no workstreams: follow First Session Protocol (`first-session.md`).
If no workplans: follow First Session Protocol (`first-session.md`).
**During work:** `record_decision()` · `add_progress_event()` · `resolve_decision()`
> State Hub is a *read model*. Bootstrap tools (`create_workstream`, `create_task`)
> are First Session Protocol only. Work structure belongs in repo files (ADR-001).
> State Hub is a *read model*. **Never register workplans or tasks by hand**
> (`create_workplan`, `create_task`, or the legacy `create_workstream`) — write
> the workplan file in `workplans/` and run `fix-consistency`; its C-06 check
> registers the workplan and its tasks in the hub and writes the IDs back into
> the file. Manual registration creates duplicates the moment fix-consistency
> runs. Work structure belongs in repo files (ADR-001).
>
> Terminology: "workstream" is the legacy name for workplan. Some API/frontmatter
> field names keep it for compatibility (`state_hub_workstream_id`,
> `workstream_id` params) — treat them as workplan IDs.
**Session close:**
With MCP tools:
```
add_progress_event(summary="...", topic_id="ca369340-a64e-442e-98f1-a4fa7dc74a38", workstream_id="<uuid>")
add_progress_event(summary="...", topic_id="ca369340-a64e-442e-98f1-a4fa7dc74a38", workplan_id="<uuid>")
```
Without MCP tools:
```bash
curl -s -X POST http://127.0.0.1:8000/progress/ \
-H "Content-Type: application/json" \
-d '{"topic_id":"ca369340-a64e-442e-98f1-a4fa7dc74a38","workstream_id":"<uuid>","event_type":"note","summary":"what changed","author":"codex"}'
-d '{"topic_id":"ca369340-a64e-442e-98f1-a4fa7dc74a38","workplan_id":"<uuid>","event_type":"note","summary":"what changed","author":"codex"}'
```
If workplan files were modified, ensure the local copy is up to date first:
If workplan files were modified, ensure the local copy is up to date first,
then sync from the repo checkout:
```bash
git -C <repo_path> pull --ff-only
cd ~/state-hub && make fix-consistency REPO=railiance-fabric
git pull --ff-only
statehub fix-consistency
```
For repos where implementation runs on a remote machine (e.g. CoulombCore),
use the combined target which pulls before fixing:
use the pull-before-fix mode from any shell with the State Hub CLI:
```bash
cd ~/state-hub && make fix-consistency-remote REPO=railiance-fabric
statehub fix-consistency --repo railiance-fabric --remote
```
**C-15** (DB task ahead of file) is normal in multi-machine workflows — writeback
will sync the file to match DB. **C-16** (repo behind remote) blocks all writes

View File

@@ -1,19 +1,14 @@
## Stack
<!-- TODO: Fill in language, frameworks, and key dependencies -->
- **Language:**
- **Key deps:**
- **Language:** Python ≥3.12 (`railiance_fabric` package)
- **Key deps:** jsonschema, PyYAML; SQLite registry at `.railiance-fabric/registry.sqlite3`
## Dev Commands
```bash
# TODO: Fill in the standard commands for this repo
# Install dependencies
# Run tests
# Lint / type check
# Build / package (if applicable)
python3 -m pytest tests/ # run the test suite
make graph-explorer # registry-backed graph explorer (HOST/PORT/REGISTRY_DB overridable)
python3 -m railiance_fabric.server --db .railiance-fabric/registry.sqlite3
```
Local-only tooling — no production deploy surface in this repo.

View File

@@ -1,28 +1,45 @@
## Workplan Convention (ADR-001)
File location: `workplans/railiance-fabric-WP-NNNN-<slug>.md`
ID prefix: `RAILIANCE-WP`
File location: `workplans/RAILIANCE-WP-NNNN-<slug>.md`
ID prefix: `RAILIANCE-WP-`
Work items originate as files in this repo **before** being registered in the hub.
Canonical workplan/workstream frontmatter statuses are:
Canonical workplan frontmatter statuses are:
`proposed`, `ready`, `active`, `blocked`, `backlog`, `finished`, `archived`.
Use `proposed` for a newly drafted plan, `ready` after review against current
repo state, and `finished` when implementation is complete. `stalled` and
`needs_review` are derived health labels, not stored statuses.
Closed workplans may be moved to `workplans/archived/` with a completion-date
prefix: `YYMMDD-railiance-fabric-WP-NNNN-<slug>.md`. The frontmatter id remains
prefix: `YYMMDD-RAILIANCE-WP-NNNN-<slug>.md`. The frontmatter id remains
unchanged; the prefix is only for quick visual reference.
Small opportunistic tasks discovered during another session use **Ad Hoc Tasks**:
`workplans/ADHOC-YYYY-MM-DD.md`, workstream slug `adhoc-YYYY-MM-DD`, and task ids
`workplans/ADHOC-YYYY-MM-DD.md`, workplan slug `adhoc-YYYY-MM-DD`, and task ids
`ADHOC-YYYY-MM-DD-T01`, `T02`, etc. Use adhocs only for low-risk work completed
directly. Promote anything requiring analysis, design, approval, dependencies, or
multiple planned phases into a normal workplan.
Ecosystem todos from other agents arrive as `[repo:railiance-fabric]` hub tasks —
visible at session start. Pick one up by creating the workplan file, then registering
the workstream.
visible at session start. Pick one up by creating the workplan file, committing,
and running `statehub fix-consistency` — C-06 registers the workplan in the hub.
Never register by hand with `create_workplan`/`create_workstream`.
Task blocks use this shape:
```task
id: RAILIANCE-WP-NNNN-T01
status: wait | todo | progress | done | cancel
priority: high | medium | low
state_hub_task_id: "<uuid>" # written by fix-consistency — do not edit
```
Status progression is `todo``progress``done`; use `wait` for waiting or
blocked work and `cancel` for stopped work.
Workplan frontmatter carries `state_hub_workstream_id` — a legacy field name
kept for compatibility ("workstream" is the old term for workplan); it holds
the hub workplan id and is written by fix-consistency. Do not edit or rename it.
<!-- Ralph Loop rules and HEUREKA sequence: ~/.claude/CLAUDE.md — do not duplicate here -->

View File

@@ -1,8 +1,8 @@
<!-- custodian-brief: generated by fix-consistency — do not edit manually -->
# Custodian Brief — railiance-fabric
**Domain:** railiance
**Last synced:** 2026-05-24 15:00 UTC
**Domain:** financials
**Last synced:** 2026-07-01 22:24 UTC
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
## Active Workstreams
@@ -13,6 +13,6 @@
## MCP Orientation (when available)
If the state-hub MCP server is reachable, call:
`get_domain_summary("railiance")`
`get_domain_summary("financials")`
This provides richer cross-domain context.
If the MCP call fails, use this file as your orientation source.

17
.repo-classification.yaml Normal file
View File

@@ -0,0 +1,17 @@
repo_classification:
standard: Repo Classification Standard
version: '1.0'
classified_at: '2026-06-22'
classified_by: agent
category: project
domain: financials
secondary_domains: []
capability_tags:
- platform
- operations
business_stake:
- technology
- operations
business_mechanics:
- coordination
- operation

View File

@@ -4,7 +4,7 @@
**Purpose:** railiance-fabric - (fill in purpose)
**Domain:** railiance
**Domain:** financials
**Repo slug:** railiance-fabric
**Topic ID:** `ca369340-a64e-442e-98f1-a4fa7dc74a38`
**Workplan prefix:** `RAILIANCE-WP-`
@@ -20,6 +20,12 @@ there is no MCP server for Codex agents.
|---------|-----|
| Local workstation | `http://127.0.0.1:8000` |
| Remote via tunnel | `http://127.0.0.1:18000` |
| Optional local edge relay | http://127.0.0.1:18080 |
When an operator has enabled the edge relay, set API_BASE to the relay URL.
Queueable writes return an explicit queued receipt if the central hub is
unreachable. Treat that as pending local evidence, then ask the operator to run
statehub outbox status/replay after connectivity returns.
### Orient at session start
@@ -27,8 +33,8 @@ there is no MCP server for Codex agents.
# Offline brief — works without hub connection
cat .custodian-brief.md
# Active workstreams for this domain
curl -s "http://127.0.0.1:8000/workstreams/?topic_id=ca369340-a64e-442e-98f1-a4fa7dc74a38&status=active" \
# Active workplans for this domain
curl -s "http://127.0.0.1:8000/workplans/?topic_id=ca369340-a64e-442e-98f1-a4fa7dc74a38&status=active" \
| python3 -m json.tool
# Check inbox
@@ -51,20 +57,20 @@ curl -s -X POST http://127.0.0.1:8000/progress/ \
"summary": "what was done",
"event_type": "note",
"author": "codex",
"workstream_id": "<uuid>",
"workplan_id": "<uuid>",
"task_id": "<uuid>"
}'
```
Omit `workstream_id` / `task_id` when not applicable.
Omit `workplan_id` / `task_id` when not applicable.
### Update task status
```bash
curl -s -X PATCH "http://127.0.0.1:8000/tasks/<task_id>" \
-H "Content-Type: application/json" \
-d '{"status": "in_progress"}'
# values: todo | in_progress | done | blocked
-d '{"status": "progress"}'
# values: wait | todo | progress | done | cancel
```
### Flag a task for human review
@@ -80,10 +86,10 @@ curl -s -X PATCH "http://127.0.0.1:8000/tasks/<task_id>" \
## Session Protocol
**Start:**
1. `cat .custodian-brief.md` — domain goal and open workstreams (offline-safe)
1. `cat .custodian-brief.md` — domain goal and open workplans (offline-safe)
2. Check inbox: `GET /messages/?to_agent=railiance-fabric&unread_only=true`; mark read
3. Scan workplans: `ls workplans/` — note `status: ready`, `active`, or `blocked` files and open tasks
4. Check blocked tasks: `GET /tasks/?needs_human=true`
4. Check human-needed tasks: `GET /tasks/?needs_human=true`
**During work:**
- Update task statuses in workplan files as tasks progress
@@ -92,12 +98,69 @@ curl -s -X PATCH "http://127.0.0.1:8000/tasks/<task_id>" \
**Close:**
1. Update workplan file task statuses to reflect progress
2. Log: `POST /progress/` with a summary of what changed
3. Note for the custodian operator: after workplan file changes, run from
`~/state-hub`:
3. After workplan file changes, run:
```bash
make fix-consistency REPO=railiance-fabric
statehub fix-consistency
```
This syncs task status from files into the hub DB.
Coding agents should run this directly; ask the operator only if the CLI or
State Hub API is unavailable. This syncs task status from files into the hub DB.
---
## Credential and access routing
**Audience:** Codex, Claude Code, Grok, and custodian agents that call **llm-connect**
for inference. Run this check **before** requesting secrets, API keys, SSH access,
login tokens, or database passwords — in any repo, not only `ops-warden`.
ops-warden **issues SSH certificates only** (`warden sign`, `cert_command`). Every
other credential need belongs to another subsystem. **Do not** message
`ops-warden` on State Hub expecting a secret value; the reply is a pointer, not a key.
### Lookup (do this first)
```bash
warden route find "<describe your need>" --json
warden route show <catalog-id> --json
```
Requires the `warden` CLI from `~/ops-warden` (`uv tool install .` or `uv run warden`).
| Agent runtime | How to orient |
| --- | --- |
| **Codex / Grok** (shell, HTTP State Hub) | `warden route` commands above; inbox `to_agent=railiance-fabric` is for coordination, not secret vending |
| **Claude Code** (MCP when available) | `get_domain_summary("custodian")` for workplans; **still** use `warden route` for credential ownership |
| **llm-connect** (inference service) | Never put secret retrieval in prompts; route custody to OpenBao/operator paths surfaced by `warden route` |
### Quick routing table
| I need… | Owner | ops-warden executes? |
| --- | --- | --- |
| SSH cert (`adm`/`agt`/`atm`) | ops-warden | **Yes** — `warden sign` |
| API key, DB password, provider token | OpenBao (`railiance-platform`) | No — route only |
| Login / OIDC / MFA | key-cape / Keycloak | No — route only |
| Authorization decision | flex-auth | No — route only |
| activity-core → issue-core emission | activity-core + issue-core | No — `warden route show activity-core-issue-sink` |
| SSH tunnel | ops-bridge (+ `cert_command` from warden) | No — route only |
### Anti-patterns (do not do these)
- `POST /messages/` to `ops-warden` asking for `ISSUE_CORE_API_KEY`, `OPENROUTER_API_KEY`, etc.
- Inventing `warden secret`, `warden login`, `warden bao`, `warden tunnel` — they do not exist
- Pasting secrets into Git, State Hub, workplans, logs, or chat
### Other capabilities (reuse-surface)
Non-credential capabilities are usually discovered through **reuse-surface** federation
(`reuse-surface` registry / `capability.*` indexes). Credential routing is inlined in
every repo's agent instructions because it is high-frequency, high-risk, and easy to
get wrong.
**Canon:** `~/ops-warden/wiki/CredentialRouting.md` · catalog `~/ops-warden/registry/routing/catalog.yaml`
<!-- REPO-AGENTS-EXTENSIONS -->
<!-- Append repo-specific agent instructions below this marker.
The state-hub template sync preserves content after this line. -->
---
@@ -124,7 +187,7 @@ anything needing analysis, design, approval, dependencies, or multiple phases.
id: RAILIANCE-WP-NNNN
type: workplan
title: "..."
domain: railiance
domain: financials
repo: railiance-fabric
status: proposed | ready | active | blocked | backlog | finished | archived
owner: codex
@@ -146,7 +209,7 @@ derived health labels, not frontmatter statuses.
` ` `task
id: RAILIANCE-WP-NNNN-T01
status: todo | in_progress | done | blocked
status: wait | todo | progress | done | cancel
priority: high | medium | low
state_hub_task_id: "<uuid>" # written by fix-consistency — do not edit
` ` `
@@ -154,7 +217,7 @@ state_hub_task_id: "<uuid>" # written by fix-consistency — do not edit
Task description text.
```
Status progression: `todo` → `in_progress` → `done` (or `blocked`)
Status progression: `todo` → `progress` → `done`; use `wait` for waiting/blocked work and `cancel` for stopped work.
To create a new workplan:
1. Write the file following the format above

View File

@@ -8,4 +8,5 @@
@.claude/rules/stack-and-commands.md
@.claude/rules/architecture.md
@.claude/rules/repo-boundary.md
@.claude/rules/credential-routing.md
@.claude/rules/agents.md

93
DECISIONS.md Normal file
View File

@@ -0,0 +1,93 @@
# Decision Log
_Auto-generated by the Custodian State Hub._
## State Hub workstation Postgres migration approval
**Date:** 2026-06-03
**Decided by:** codex
Superseded by WP-0004 T09 cancellation and CUST-WP-0038 ownership of State Hub HA migration, including hostname, registry, exposure model, HA database/storage, restore drills, and production data migration approval.
---
## activity-core deployment architecture
**Date:** 2026-06-03
**Decided by:** codex
Superseded by completed WP-0004 outcome: activity-core was deployed as a K3s production service on railiance01 on 2026-05-22; the packaging architecture question is no longer blocking this workplan.
---
## Review CCR-2026-0001 whynot-design npm publish token lane
**Date:** 2026-06-27
**Decided by:** human
APPROVE: scoped path and confirmed binding are acceptable
---
## Review CCR-2026-0001 corrected whynot-design npm publish token lane
**Date:** 2026-06-27
**Decided by:** human
APPROVE: We fixed the path using coulomb as the org/tenant.
---
## Forgejo hostname and exposure model
**Date:** 2026-07-02
**Decided by:** human
the hostname shall be forgejo.coulomb.social. The exposure model is private repos by default. We will use the transition from gitea to forgejo for closing down public access and establishing credential handling to have convenience when working with the repos. Gitea can and should remain reachable during transition.
---
## Forgejo SMTP and sender identity
**Date:** 2026-07-02
**Decided by:** human
We will use forgejo@coulomb.social
---
## Forgejo package registry scope
**Date:** 2026-07-02
**Decided by:** human
We should support the full range from the start.
---
## Forgejo Actions runner isolation model
**Date:** 2026-07-02
**Decided by:** human
we will try to go with isolated host runners, with least-privilege credential boundaries.
---
## Forgejo backup target and restore cadence
**Date:** 2026-07-02
**Decided by:** human
We will need to figure out the details, but i want to use backup.coulomb.social as the hostname with a backend we need to figure out yet.
---
## Forgejo cutover and rollback strategy
**Date:** 2026-07-02
**Decided by:** human
We will do a staged migration and lock the gitea repos of transitioned repos but keep gitea until everything has been transfered and just then start a 14day trial phase and after that retire gitea to the backup.
---

21
Makefile Normal file
View File

@@ -0,0 +1,21 @@
PYTHON ?= python3
REGISTRY_DB ?= .railiance-fabric/registry.sqlite3
HOST ?= 127.0.0.1
PORT ?= 8765
.DEFAULT_GOAL := help
.PHONY: help graph-explorer registry
help:
@printf "Available targets:\n"
@printf " make graph-explorer Start the registry-backed graph explorer on HOST:PORT.\n"
@printf " Defaults: HOST=$(HOST), PORT=$(PORT), REGISTRY_DB=$(REGISTRY_DB)\n"
@printf " make registry Alias for graph-explorer.\n"
graph-explorer:
@mkdir -p $(dir $(REGISTRY_DB))
@echo "Starting Railiance Fabric graph explorer at http://$(HOST):$(PORT)/ui/graph-explorer"
$(PYTHON) -m railiance_fabric.server --db "$(REGISTRY_DB)" --host "$(HOST)" --port "$(PORT)"
registry: graph-explorer

View File

@@ -81,7 +81,22 @@ See `docs/ecosystem-registry-service.md` for the standards comparison and
service direction for registering repos and interacting with the combined
ecosystem model. See `docs/registry-api.md` for the current registry HTTP API.
Start the first registry service slice with:
List available Make targets from the repo root:
```bash
make
```
Start the first registry service slice and graph explorer explicitly:
```bash
make graph-explorer
```
The target serves `http://127.0.0.1:8765/ui/graph-explorer` by default. Override
`PORT`, `HOST`, or `REGISTRY_DB` if the local port or database path differs.
Equivalent raw command:
```bash
railiance-fabric-registry --db .railiance-fabric/registry.sqlite3 --port 8765
@@ -136,5 +151,6 @@ loop.
The graph explorer export is the first executable slice of the interactive
Fabric map. See `docs/graph-explorer-transfer-review.md` for the repo-scoping
transfer review, `docs/graph-explorer-contract.md` for the shared manifest and
payload contract, and `docs/graph-explorer-operations.md` for launch, refresh,
verification, and extraction guidance.
payload contract, `docs/semantic-attractors.md` for the attractor-based layout
orientation concept, and `docs/graph-explorer-operations.md` for launch,
refresh, verification, and extraction guidance.

View File

@@ -87,6 +87,80 @@ spec:
- sts-token
tags: [storage, credentials, security]
- id: kubernetes-runtime
name: Kubernetes runtime
lifecycle: active
description: Provides the Kubernetes API, namespaces, workloads, Services, Ingresses, and runtime primitives consumed by Railiance services.
default_criticality: critical
default_data_classification: restricted
expected_interface_types:
- kubernetes-api
- kubernetes-crd
tags: [kubernetes, cluster, runtime]
- id: ci-cd-template-catalog
name: CI/CD template catalog
lifecycle: planned
description: Provides reusable workflow templates, release gates, and delivery conventions for Railiance workloads.
default_criticality: medium
default_data_classification: internal
expected_interface_types:
- workflow-template-contract
- cli
tags: [ci, cd, gitops, enablement]
- id: source-hosting
name: Source hosting
lifecycle: active
description: Hosts Git repositories, repository metadata, review surfaces, and source-forge web/API access.
default_criticality: high
default_data_classification: confidential
expected_interface_types:
- web-ui
- http-api
- git-ssh
tags: [forge, git, source]
- id: container-registry
name: Container registry
lifecycle: active
description: Publishes and serves OCI container images for Railiance workloads.
default_criticality: high
default_data_classification: confidential
expected_interface_types:
- oci-registry
tags: [forge, registry, container-image]
- id: python-package-registry
name: Python package registry
lifecycle: active
description: Publishes and serves Python package artifacts for Railiance source and app builds.
default_criticality: high
default_data_classification: confidential
expected_interface_types:
- python-package-index
tags: [forge, registry, python, package]
- id: workflow-runner-substrate
name: Workflow runner substrate
lifecycle: planned
description: Provides forge-backed runner infrastructure, labels, placement, and credential boundaries for workflows.
default_criticality: high
default_data_classification: restricted
expected_interface_types:
- workflow-runner-label-contract
tags: [forge, runner, actions, automation]
- id: artifact-promotion-evidence
name: Artifact promotion evidence
lifecycle: active
description: Provides release artifact identity, provenance, publish, restore, and readiness evidence for consumers.
default_criticality: high
default_data_classification: internal
expected_interface_types:
- evidence-contract
tags: [forge, evidence, provenance, release]
- id: audit-event-sink
name: Audit/event sink
lifecycle: planned

View File

@@ -57,6 +57,14 @@ spec:
typical_auth_methods: [kubernetes_service_account]
versioning: group, version, and kind.
- id: kubernetes-api
name: Kubernetes API
lifecycle: active
description: Kubernetes API server surface consumed by operators, controllers, and automation.
category: kubernetes
typical_auth_methods: [kubernetes_service_account, oidc, static_secret]
versioning: Kubernetes version, API groups, RBAC contract, and kubeconfig delivery path.
- id: helm-release
name: Helm release
lifecycle: active
@@ -81,6 +89,54 @@ spec:
typical_auth_methods: [database_role, static_secret, openbao_token]
versioning: engine version, connection contract, and migration compatibility.
- id: git-ssh
name: Git SSH
lifecycle: active
description: Git-over-SSH repository access endpoint.
category: source-control
typical_auth_methods: [static_secret, unknown]
versioning: hostname, port, SSH host key, authorized key scope, and Git server compatibility.
- id: oci-registry
name: OCI registry
lifecycle: active
description: OCI distribution-compatible container image registry endpoint.
category: registry
typical_auth_methods: [api_key, static_secret, none]
versioning: registry host, API behavior, package visibility, and tag/digest semantics.
- id: python-package-index
name: Python package index
lifecycle: active
description: Python package index endpoint compatible with pip/uv simple API consumption.
category: registry
typical_auth_methods: [api_key, static_secret, none]
versioning: package index URL, package visibility, token scope, and package version semantics.
- id: workflow-runner-label-contract
name: Workflow runner label contract
lifecycle: planned
description: Published runner label, placement, and trust contract consumed by CI/CD workflows.
category: automation
typical_auth_methods: [none, kubernetes_service_account, static_secret]
versioning: semantic label names, trust level, credential purpose, and runner replacement rules.
- id: workflow-template-contract
name: Workflow template contract
lifecycle: planned
description: Reusable CI/CD workflow template or template catalog contract.
category: automation
typical_auth_methods: [none]
versioning: template id, input schema, runner labels, and release gate semantics.
- id: evidence-contract
name: Evidence contract
lifecycle: active
description: Documented evidence bundle or machine-readable evidence contract for release, restore, or readiness decisions.
category: evidence
typical_auth_methods: [none, api_key]
versioning: evidence schema version, required fields, source links, and retention policy.
- id: object-storage-bucket
name: Object-storage bucket
lifecycle: planned

View File

@@ -169,6 +169,70 @@ introduce a two-phase layout:
This will likely require an internal view model that separates fabric graph data
from rendered graph coordinates.
### Per-Zone Layout Preparation
The current graph explorer should not immediately run independent Cytoscape
layouts inside each zone rectangle. Cytoscape layouts operate on collections in
one coordinate space, while the current zone overlay is a view layer drawn over
the already-laid-out graph. Running nested layouts directly against visible
nodes would make pan/zoom, filters, collapse state, and edge routing fragile.
The safer path is a two-phase view layout:
1. Resolve zones from the current graph and view filters.
2. Place zone containers and unzoned nodes in the global canvas.
3. For each zone, compute local coordinates for its assigned nodes using the
zone's configured layout algorithm.
4. Project local zone coordinates into global graph coordinates.
5. Route internal edges inside the zone and boundary edges through the zone
perimeter or collapsed zone node.
The implementation needs these pieces before per-zone layouts become safe:
- a resolved zone view model that survives filtering and saved profiles;
- a stable assignment invariant so a visible node belongs to no more than one
zone;
- a zone container model with size, position, padding, and height;
- a local coordinate projection layer from zone space to Cytoscape space;
- explicit boundary-edge routing rules;
- collapse state that can replace a zone subgraph with a representative node;
- diagnostics when a configured zone layout cannot be applied.
The present implementation already establishes the first, second, and sixth
pieces. A follow-up should introduce a zone container placement phase before
attempting per-zone node layout. That follow-up can keep Cytoscape as the final
renderer while moving layout decisions into a Fabric-owned view model.
### Stable Zone Containers
The first container implementation keeps zone surfaces as view state keyed by
stable zone id. When a zone first appears, the global graph layout supplies its
initial center. Once created, the container owns the zone surface position while
the global layout continues to arrange the base canvas and unzoned nodes.
Dragging a zone moves the container and its currently assigned visible member
nodes together. Rerunning layout or switching the layout algorithm should keep
the container in its stored graph coordinates and then project the zone's
visible subgraph back into that container.
Container state belongs in saved or copied graph view state, not in the Fabric
payload. It is an operator workspace preference, similar to manual visibility
overrides.
Zone-local layout is also view state. The first selectable algorithms are a
compact grid and a circle layout. Switching between them should rearrange the
assigned nodes inside each stable container without moving the container itself
or changing the underlying Fabric relationships.
### Context Edges
Display-only context edges are not zone connectivity. Repository `declares`
edges, for example, show which repository declared a node, but they should not
create boundary diagnostics, attraction paths, or collapsed-zone boundary
edges. A host can still show them as explanatory evidence in details, but a
zone boundary should only react to canonical or host-promoted graph
relationships.
## Layer Height And Overlap
Zone presentation includes a height. Height is a visual stacking concept, not a

View File

@@ -104,6 +104,32 @@ edges are intentionally shortest and most elastic; deployment-to-repo edges are
longer and looser so infrastructure placement does not collapse into the repo
node.
## Semantic Attractor Modes
Semantic attractors are view-only topic poles that can pull graph entities
toward conceptual neighborhoods in spring-based layouts. For repository maps,
an operator might choose attractors such as `security`, `development`, and
`operations`; Fabric can then score each repository's semantic closeness to
those attractors from repo-owned `SCOPE.md` evidence and map the score to
layout strength.
Attractors are not domain edges and do not change Fabric graph data. They may
be materialized as synthetic display-only nodes and `semantic_attraction`
edges, or carried as top-level view metadata that the renderer turns into
layout forces. Attraction scores should remain inspectable, with source
references and confidence, so the operator can understand why a repository was
pulled toward a topic.
Unlike zones, attractors may overlap. A repository can be close to both
`development` and `operations`, and the layout should place it between those
poles. Zone resolvers, boundary diagnostics, dependency queries, blast-radius
queries, and collapsed-zone boundary edges should ignore semantic attraction
edges unless a host explicitly promotes an attractor relation into canonical
graph data.
See `docs/semantic-attractors.md` for the concept model, scoring semantics,
payload direction, and implementation path.
## Display State Ownership
The contract allows either the host service or the engine to evaluate display
@@ -156,7 +182,9 @@ reach it here?" without mutating the underlying Fabric responsibility boundary.
Zone boundary overlays are a visual layer over the graph canvas. They should be
computed from visible node positions after layout/filtering rather than modeled
as graph parent nodes. The default boundary grouping is `deploymentEnvironment`:
as graph parent nodes. The overlay should be backed by explicit zone definitions
and a resolver so visible nodes are assigned to at most one rendered zone. The
default boundary grouping is `deploymentEnvironment`:
| Overlay label | Matching nodes |
|---------------|----------------|
@@ -171,6 +199,11 @@ When access-zone grouping is selected, boundaries use `accessZone` values such
as `private-dev`, `collaborator-test`, `production-public`, or
`production-admin`.
Zone labels should be rendered as plain text in the upper-left corner of the
zone rectangle, without badge frames or white backgrounds. The label may still
act as the zone's focus/drag handle as long as it visually reads as text drawn
on the zone surface.
Useful warnings for the graph explorer include:
- control surfaces in user-facing access zones;
@@ -180,6 +213,46 @@ Useful warnings for the graph explorer include:
- local-only surfaces that appear in shared or production scenarios;
- conflicting port or host claims within the same deployment scenario.
Zone resolvers should also expose scoped diagnostics in zone detail panels. The
initial diagnostic set includes empty zone seed sets, visible nodes matched by
multiple zone definitions, and edges crossing zone boundaries. Attraction
diagnostics such as multiple attraction candidates or depth-limit stops belong
to the same resolver diagnostic channel when attraction rules are enabled.
Display-only context edges, such as repository `declares` edges, are evidence
for where declarations came from. They must not count as zone boundary
connectivity, attraction paths, or collapsed-zone boundary edges unless a host
explicitly promotes them to canonical graph relationships.
Saved graph profiles should persist zone view state as an explicit nested
`zone` object. The initial fields are `visible`, `grouping`, `definitionSet`,
`presentation`, and `containers`. URL parameters may continue to expose
compatibility aliases such as `zoneBoundaries`, `zoneGrouping`, and
`zoneDefinitionSet`, but saved profiles should prefer the nested object so
future zone definition sets, presentation preferences, and operator-placed zone
surfaces can be restored without another state migration.
Zone containers are view state, not fabric data. A container stores a stable
zone surface position and size in graph coordinates. Global graph layout may
place unzoned nodes and provide an initial center for new zones, but existing
zone containers should keep their operator-chosen positions when the layout
algorithm changes. After the global layout pass, each zone may project its
assigned visible nodes into local coordinates inside its container. The current
local layout choices are compact grid and circle. The selected zone-local
layout algorithm belongs in the nested `zone.layout.algorithm` view state so it
can be restored by saved or copied views without changing the Fabric payload.
Zone collapse is a view-only operation. A collapsed zone should hide its visible
member nodes, replace them with a synthetic zone node, and draw synthetic
boundary edges from that zone node to visible external neighbors. Internal edges
are summarized on the zone node rather than rendered. Expanding the zone removes
the synthetic elements and restores the original graph elements without
changing the underlying payload.
Zone dragging is also view-only. Dragging a zone handle should translate the
currently assigned visible member nodes by the same delta and then recompute the
overlay bounds from the new node positions. The operation updates Cytoscape view
coordinates only; it does not change Fabric graph data.
## Repo-Scoping Compatibility
Repo-scoping can adapt without a rewrite because its current graph payload

View File

@@ -6,18 +6,38 @@ verified, and how to extract the shared engine once the second adapter is ready.
## Launch
Start the registry against the local SQLite database:
List available Make targets from the repo root:
```bash
railiance-fabric-registry --db .railiance-fabric/registry.sqlite3 --port 8765
make
```
Open the map:
Start the registry-backed graph explorer explicitly:
```bash
make graph-explorer
```
This serves the graph explorer at:
```text
http://127.0.0.1:8765/ui/graph-explorer
```
The target defaults to `.railiance-fabric/registry.sqlite3`, host
`127.0.0.1`, and port `8765`. Override those when needed:
```bash
make graph-explorer PORT=8876
make graph-explorer HOST=0.0.0.0 PORT=8765 REGISTRY_DB=/tmp/railiance-fabric.sqlite3
```
Equivalent raw command:
```bash
railiance-fabric-registry --db .railiance-fabric/registry.sqlite3 --port 8765
```
Useful supporting endpoints:
```text

340
docs/semantic-attractors.md Normal file
View File

@@ -0,0 +1,340 @@
# Semantic Attractors
## Intent
Semantic attractors are view entities that help an operator orient inside a
medium or large graph. An attractor represents a topic, concern, capability
area, operating mode, or other conceptual pole such as `security`,
`development`, `operations`, `identity`, `data`, or `delivery`.
The graph explorer can place attractors on the canvas and connect graph
entities to them with view-only relationship strength. The stronger an
entity's semantic closeness to an attractor, the more that attractor should
pull the entity in force-directed or spring-based layouts.
The first motivating use case is repository orientation. Given a set of
repositories, the operator defines attractors such as `security`,
`development`, and `operations`. Railiance Fabric reads each repository's
`SCOPE.md`, estimates semantic closeness to those attractors, and maps that
score to layout force. The resulting map becomes a navigational surface: repos
with similar purpose drift toward the same conceptual pole without replacing
the underlying dependency or responsibility graph.
## What Attractors Are
An attractor is not a fabric node in the source graph. It is a graph-view
artifact with these responsibilities:
- name a topic or concern that is useful for orientation;
- define how closeness to that topic is measured;
- expose a score for each eligible entity;
- translate that score into layout hints and optional visual edges;
- keep the scoring evidence inspectable so the map does not become mysterious.
Attractors should be saved as view/profile configuration, operator presets, or
host-provided explorer configuration. They should not mutate repo-owned Fabric
declarations, and they should not imply that a repository provides or consumes
a capability.
## Why This Helps
Dependency edges answer "what depends on what?" Ownership and deployment
metadata answer "who owns this?" and "where does this run?" Those questions are
necessary, but they can still leave a large repo collection hard to scan.
Attractors answer a softer question: "what is this near, conceptually?"
This gives operators a fast way to discover clusters such as:
- repos that are security-heavy but not obvious from their names;
- operations tooling that depends on development systems;
- application repos that are unexpectedly close to platform/runtime concerns;
- thin adapter repos that sit between two conceptual poles;
- orphaned or ambiguous repos that have weak attraction to every known topic.
## Core Model
An attractor definition should be serializable and stable:
```yaml
id: security
label: Security
description: Identity, authorization, secrets, MFA, audit, policy, and trust boundaries.
applies_to:
layers: [repository]
evidence:
sources:
- type: scope_markdown
path: SCOPE.md
scoring:
method: lexical_semantic_profile
anchors:
- security
- identity
- authorization
- secrets
- audit
- policy
- mfa
negative_anchors:
- unrelated
normalization:
mode: per_entity_softmax
layout:
min_score: 0.15
max_score: 1.0
strength_scale: 0.8
ideal_length:
min: 80
max: 420
presentation:
color: "#be123c"
edge_style: dashed
```
The exact schema can evolve, but the responsibilities should remain separate:
- `applies_to` chooses which graph elements can be scored.
- `evidence` declares which text or metadata is used.
- `scoring` defines the semantic metric.
- `normalization` turns raw scores into comparable view weights.
- `layout` maps weights to graph layout hints.
- `presentation` controls the optional visual attractor node and edges.
## Scoring From SCOPE.md
`SCOPE.md` is a useful first evidence source because it is intentionally short,
repo-owned, and written to explain when a repository is relevant. For repository
attraction, the scorer should use sections such as:
- `One-liner`
- `Core Idea`
- `In Scope`
- `Relevant When`
- `Provided Capabilities`
- `Related / Overlapping Repositories`
- `Terminology`
Sections such as `Out of Scope` and `Not Relevant When` should be used
carefully. They can reduce false positives, but they should not erase a topic
just because the repo mentions a boundary. For example, a repo can say it is
not an authorization engine while still being semantically near security
because it models secrets, policy, or trust boundaries.
The first implementation can use a transparent lexical profile:
1. Parse `SCOPE.md` into sections.
2. Tokenize section text and provided capability keywords.
3. Weight section matches, with `One-liner`, `Core Idea`, `In Scope`, and
capability keywords carrying more weight than incidental notes.
4. Score each attractor by matching configured anchors and related terms.
5. Normalize scores per entity so one verbose `SCOPE.md` does not dominate.
6. Store the score, confidence, and top evidence snippets in the view payload.
Later implementations can replace or augment lexical scoring with embeddings,
LLM-assisted classification, or operator-reviewed labels. The contract should
not depend on a particular scorer.
## Score Semantics
Attractor scores should be continuous values in `[0, 1]`.
Suggested interpretation:
| Score | Meaning |
|-------|---------|
| `0.00` | no useful evidence of semantic closeness |
| `0.10` to `0.30` | weak signal; useful only as a faint layout hint |
| `0.30` to `0.60` | moderate closeness; entity should visibly lean toward the attractor |
| `0.60` to `0.85` | strong closeness; entity likely belongs near the attractor cluster |
| `0.85` to `1.00` | primary semantic identity or explicit operator label |
Every score should carry a confidence separate from closeness. A repo with a
thin or missing `SCOPE.md` may have low confidence even if a few terms match.
Attractors should also support multi-attraction. A repository can be close to
both `development` and `operations`; the layout should then place it between
those poles instead of forcing a single category. This is the main difference
from zones: zones preserve a single-surface invariant, while attractors are
allowed to overlap because they are layout forces, not containers.
## Layout Mapping
Attraction scores become layout hints. They should not become domain edges.
A graph explorer can map scores to synthetic view edges:
```json
{
"data": {
"id": "attractor:security->repo:flex-auth",
"source": "attractor:security",
"target": "repo:flex-auth",
"edgeType": "semantic_attraction",
"displayOnly": true,
"score": 0.82,
"confidence": 0.74,
"strength": "strong",
"layoutAffinity": 0.82,
"layoutIdealLength": 110,
"layoutElasticity": 0.9,
"sourceReferences": [
{
"type": "scope_markdown",
"path": "SCOPE.md",
"section": "In Scope"
}
]
},
"classes": "semantic-attraction"
}
```
For force-directed layouts:
- stronger scores should increase spring strength or edge weight;
- stronger scores should shorten ideal length;
- weak scores may be hidden visually while still applying a small force;
- edges below a configured threshold should not affect layout;
- display-only attraction edges should be excluded from dependency, boundary,
blast-radius, and zone-connectivity diagnostics.
Attractor nodes can be pinned, arranged on a ring, placed by the operator, or
computed from the current profile. For first use, a stable radial placement is
usually enough: place three to eight attractors around the graph, then let
repositories find their balance.
## View Payload Shape
The graph explorer payload should be able to carry attractor metadata without
changing the canonical Fabric graph.
Recommended top-level view extension:
```json
{
"view": {
"attractors": {
"enabled": true,
"definitionSet": "repo-concerns-v1",
"definitions": [
{
"id": "security",
"label": "Security",
"description": "Identity, authorization, secrets, audit, and policy.",
"color": "#be123c"
}
],
"scores": [
{
"attractor_id": "security",
"element_id": "repo:flex-auth",
"score": 0.82,
"confidence": 0.74,
"method": "lexical_semantic_profile",
"evidence": [
{
"source": "SCOPE.md",
"section": "Core Idea",
"terms": ["authorization", "policy"]
}
]
}
]
}
}
}
```
The renderer may choose to materialize these into synthetic nodes and edges at
runtime. A host may also emit synthetic display-only elements directly if that
is easier for the current engine.
## Operator Workflow
A useful attractor workflow should feel like mapmaking:
1. Choose a preset such as `Security / Development / Operations`.
2. Review the generated scores and evidence for a few known repos.
3. Hide or pin attractors that are not useful for the current question.
4. Save the attractor definition set in the graph profile.
5. Use the resulting layout to discover ambiguous, central, or misplaced repos.
The UI should expose:
- a toggle for semantic attractors;
- a definition-set selector;
- score threshold controls;
- optional visual attraction edges;
- pinned/unpinned attractor placement;
- detail panels explaining why a repo is close to an attractor;
- diagnostics for missing evidence, low confidence, and overly broad
attractors.
## Relationship To Zones
Zones and attractors solve different orientation problems.
Zones are bounded drawing surfaces. A visible node belongs to zero or one zone
in a given view. They are useful for deployment environments, access zones,
ownership surfaces, and other container-like questions.
Attractors are semantic force points. A visible node can be pulled by multiple
attractors at once. They are useful for topical orientation, concern mapping,
and discovering conceptual neighborhoods.
The two concepts can combine cleanly:
- zones can show where entities run;
- attractors can pull repos inside or outside those zones based on semantic
concern;
- zone diagnostics should ignore semantic attraction edges unless explicitly
configured otherwise;
- attractor scores can be summarized inside zone details.
## Initial Presets
A first repository-orientation preset should keep the set small:
| Attractor | Topic Signal |
|-----------|--------------|
| `security` | identity, secrets, authorization, policy, audit, MFA, trust boundaries |
| `development` | source code, build, CI/CD, package publishing, scaffolding, developer workflows |
| `operations` | deployment, runtime, monitoring, backups, incidents, infrastructure lifecycle |
Useful follow-up presets:
- `data`, `identity`, `delivery`, `governance`
- `platform`, `application`, `tooling`
- `financial`, `runtime`, `coordination`
Attractors should start as operator-chosen presets rather than global truth.
The same repository can be viewed through different conceptual lenses.
## Implementation Path
The concept can be implemented incrementally:
1. Add an attractor definition format for graph explorer profiles.
2. Parse repo `SCOPE.md` files during registry sync or graph export.
3. Compute transparent lexical scores for repositories.
4. Include attractor scores and evidence in the graph explorer payload.
5. Add synthetic attractor nodes and display-only attraction edges in the UI.
6. Map attraction scores to layout hints for the force-directed layout.
7. Add detail-panel evidence and low-confidence diagnostics.
8. Support saved attractor presets and operator score overrides.
This keeps attractors as a view concern until the scoring model proves useful.
If a semantic relation becomes durable domain knowledge, it can later be
promoted into a proper Fabric declaration with separate evidence and review.
## Open Questions
- Should attractor definitions live in graph profiles, repo config, or a shared
registry preset file?
- Should scoring run during registry sync, export, or entirely in the browser?
- How much operator override should be allowed before scores become maintained
labels rather than computed evidence?
- What is the right default for missing or stale `SCOPE.md` evidence?
- Should the first implementation use only lexical scoring, or should it also
prepare a pluggable embedding scorer interface?

View File

@@ -0,0 +1,16 @@
apiVersion: railiance.fabric/v1alpha1
kind: BindingAssertion
metadata:
id: railiance-apps.s5-releases.artifact-evidence-to-forge
name: S5 artifact evidence binding
owner: railiance-apps
repo: railiance-apps
domain: railiance
spec:
lifecycle: active
environments: [dev, staging, prod]
dependency_id: railiance-apps.s5-releases.needs-artifact-evidence
provider_capability_id: railiance-forge.source-forge.artifact-promotion-evidence
provider_interface_id: railiance-forge.source-forge.evidence-contract
status: compatible
rationale: S5 release readiness should cite forge-owned artifact publish, restore, and operating evidence.

View File

@@ -0,0 +1,16 @@
apiVersion: railiance.fabric/v1alpha1
kind: BindingAssertion
metadata:
id: railiance-apps.s5-releases.container-registry-to-forge
name: S5 container registry binding
owner: railiance-apps
repo: railiance-apps
domain: railiance
spec:
lifecycle: active
environments: [dev, staging, prod]
dependency_id: railiance-apps.s5-releases.needs-container-registry
provider_capability_id: railiance-forge.source-forge.container-registry
provider_interface_id: railiance-forge.source-forge.oci-registry
status: compatible
rationale: S5 releases consume already-published app images from the forge-owned OCI registry.

View File

@@ -0,0 +1,16 @@
apiVersion: railiance.fabric/v1alpha1
kind: BindingAssertion
metadata:
id: railiance-enablement.delivery-templates.runner-substrate-to-forge
name: Enablement runner substrate binding
owner: railiance-enablement
repo: railiance-enablement
domain: railiance
spec:
lifecycle: planned
environments: [dev, staging, prod]
dependency_id: railiance-enablement.delivery-templates.needs-runner-substrate
provider_capability_id: railiance-forge.source-forge.workflow-runner-substrate
provider_interface_id: railiance-forge.source-forge.runner-label-contract
status: compatible
rationale: S4 reusable templates should consume forge-owned runner labels, trust posture, and runner evidence.

View File

@@ -0,0 +1,16 @@
apiVersion: railiance.fabric/v1alpha1
kind: BindingAssertion
metadata:
id: railiance-forge.source-forge.kubernetes-runtime-to-cluster
name: Forge Kubernetes runtime binding
owner: railiance-forge
repo: railiance-forge
domain: railiance
spec:
lifecycle: active
environments: [dev, staging, prod]
dependency_id: railiance-forge.source-forge.needs-kubernetes-runtime
provider_capability_id: railiance-cluster.kubernetes.runtime
provider_interface_id: railiance-cluster.kubernetes.api
status: compatible
rationale: The forge runtime is deployed on the Railiance Kubernetes runtime provided by railiance-cluster.

View File

@@ -0,0 +1,16 @@
apiVersion: railiance.fabric/v1alpha1
kind: BindingAssertion
metadata:
id: railiance-forge.source-forge.object-storage-to-artifact-store
name: Forge object storage binding
owner: railiance-forge
repo: railiance-forge
domain: railiance
spec:
lifecycle: planned
environments: [dev, staging, prod]
dependency_id: railiance-forge.source-forge.needs-object-storage
provider_capability_id: artifact-store.object-storage
provider_interface_id: artifact-store.object-storage.bucket
status: compatible
rationale: Durable forge artifact/blob preservation should use the planned Railiance object-storage provider rather than ad hoc forge-local storage.

View File

@@ -0,0 +1,16 @@
apiVersion: railiance.fabric/v1alpha1
kind: BindingAssertion
metadata:
id: railiance-forge.source-forge.postgresql-to-cnpg
name: Forge PostgreSQL binding
owner: railiance-forge
repo: railiance-forge
domain: railiance
spec:
lifecycle: active
environments: [dev, staging, prod]
dependency_id: railiance-forge.source-forge.needs-postgresql
provider_capability_id: railiance-platform.cnpg.postgresql
provider_interface_id: railiance-platform.cnpg.database-connection
status: compatible
rationale: Current Gitea database state is backed by the Railiance platform CNPG PostgreSQL service.

View File

@@ -0,0 +1,16 @@
apiVersion: railiance.fabric/v1alpha1
kind: BindingAssertion
metadata:
id: railiance-forge.source-forge.runtime-secrets-to-openbao
name: Forge runtime secrets binding
owner: railiance-forge
repo: railiance-forge
domain: railiance
spec:
lifecycle: active
environments: [dev, staging, prod]
dependency_id: railiance-forge.source-forge.needs-runtime-secrets
provider_capability_id: railiance-platform.openbao.runtime-secrets
provider_interface_id: railiance-platform.openbao.kv-v2
status: compatible
rationale: Runtime secret custody for forge workloads belongs to the platform OpenBao path; SOPS/age remains bootstrap only.

View File

@@ -0,0 +1,21 @@
apiVersion: railiance.fabric/v1alpha1
kind: CapabilityDeclaration
metadata:
id: railiance-cluster.kubernetes.runtime
name: Kubernetes runtime
owner: railiance-cluster
repo: railiance-cluster
domain: railiance
source_links:
- label: Cluster scope
path: /home/worsch/railiance-cluster/SCOPE.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: Provides Kubernetes runtime primitives and API access consumed by Railiance platform, forge, and app workloads.
capability_type: kubernetes-runtime
service_id: railiance-cluster.kubernetes
interface_ids:
- railiance-cluster.kubernetes.api
criticality: critical
data_classification: restricted

View File

@@ -0,0 +1,23 @@
apiVersion: railiance.fabric/v1alpha1
kind: CapabilityDeclaration
metadata:
id: railiance-enablement.delivery-templates.ci-cd-templates
name: CI/CD workflow templates
owner: railiance-enablement
repo: railiance-enablement
domain: railiance
source_links:
- label: Enablement scope
path: /home/worsch/railiance-enablement/SCOPE.md
- label: Enablement intent
path: /home/worsch/railiance-enablement/INTENT.md
spec:
lifecycle: planned
environments: [dev, staging, prod]
description: Reusable Railiance workflow templates, promotion conventions, and delivery gates that consume forge runner labels and artifact evidence.
capability_type: ci-cd-template-catalog
service_id: railiance-enablement.delivery-templates
interface_ids:
- railiance-enablement.delivery-templates.workflow-template-contract
criticality: medium
data_classification: internal

View File

@@ -0,0 +1,23 @@
apiVersion: railiance.fabric/v1alpha1
kind: CapabilityDeclaration
metadata:
id: railiance-forge.source-forge.artifact-promotion-evidence
name: Artifact promotion evidence
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Observability and evidence contract
path: /home/worsch/railiance-forge/docs/observability-operating-evidence.md
- label: Backup and restore handoff
path: /home/worsch/railiance-forge/docs/backup-restore-secret-handoff.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: Provides artifact identity, provenance, publish, restore, and release-readiness evidence that downstream releases can cite.
capability_type: artifact-promotion-evidence
service_id: railiance-forge.source-forge
interface_ids:
- railiance-forge.source-forge.evidence-contract
criticality: high
data_classification: internal

View File

@@ -0,0 +1,21 @@
apiVersion: railiance.fabric/v1alpha1
kind: CapabilityDeclaration
metadata:
id: railiance-forge.source-forge.container-registry
name: Container registry
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Container registry docs
path: /home/worsch/railiance-forge/docs/gitea-container-registry.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: Provides the Gitea OCI container registry endpoint used by Railiance workloads.
capability_type: container-registry
service_id: railiance-forge.source-forge
interface_ids:
- railiance-forge.source-forge.oci-registry
criticality: high
data_classification: confidential

View File

@@ -0,0 +1,21 @@
apiVersion: railiance.fabric/v1alpha1
kind: CapabilityDeclaration
metadata:
id: railiance-forge.source-forge.python-package-registry
name: Python package registry
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Package registry docs
path: /home/worsch/railiance-forge/docs/gitea-package-registry.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: Provides the Gitea Python package registry endpoint used by Railiance source and app builds.
capability_type: python-package-registry
service_id: railiance-forge.source-forge
interface_ids:
- railiance-forge.source-forge.python-package-index
criticality: high
data_classification: confidential

View File

@@ -0,0 +1,22 @@
apiVersion: railiance.fabric/v1alpha1
kind: CapabilityDeclaration
metadata:
id: railiance-forge.source-forge.source-hosting
name: Source hosting
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Forge scope
path: /home/worsch/railiance-forge/SCOPE.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: Hosts Railiance Git repositories, review surfaces, repository metadata, and source-forge access paths.
capability_type: source-hosting
service_id: railiance-forge.source-forge
interface_ids:
- railiance-forge.source-forge.web-ui
- railiance-forge.source-forge.git-ssh
criticality: high
data_classification: confidential

View File

@@ -0,0 +1,21 @@
apiVersion: railiance.fabric/v1alpha1
kind: CapabilityDeclaration
metadata:
id: railiance-forge.source-forge.workflow-runner-substrate
name: Workflow runner substrate
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Runner ownership contract
path: /home/worsch/railiance-forge/docs/ci-runner-actions-gitops-ownership.md
spec:
lifecycle: planned
environments: [dev, staging, prod]
description: Provides forge-backed runner labels, placement, credential boundaries, and runner health evidence consumed by workflow templates and release checks.
capability_type: workflow-runner-substrate
service_id: railiance-forge.source-forge
interface_ids:
- railiance-forge.source-forge.runner-label-contract
criticality: high
data_classification: restricted

View File

@@ -0,0 +1,30 @@
apiVersion: railiance.fabric/v1alpha1
kind: DependencyDeclaration
metadata:
id: railiance-apps.s5-releases.needs-artifact-evidence
name: S5 artifact evidence dependency
owner: railiance-apps
repo: railiance-apps
domain: railiance
source_links:
- label: Apps scope
path: /home/worsch/railiance-apps/SCOPE.md
- label: Observability and evidence contract
path: /home/worsch/railiance-forge/docs/observability-operating-evidence.md
spec:
lifecycle: active
environments: [dev, staging, prod]
consumer_service_id: railiance-apps.s5-releases
requires:
capability_type: artifact-promotion-evidence
capability_id: railiance-forge.source-forge.artifact-promotion-evidence
interface:
type: evidence-contract
version_constraint: ">=v1"
auth:
method: none
criticality: high
data_classification: internal
fallback:
mode: manual
description: App operators can record manual evidence, but S5 should cite forge-owned artifact readiness when promoting releases.

View File

@@ -0,0 +1,30 @@
apiVersion: railiance.fabric/v1alpha1
kind: DependencyDeclaration
metadata:
id: railiance-apps.s5-releases.needs-container-registry
name: S5 container registry dependency
owner: railiance-apps
repo: railiance-apps
domain: railiance
source_links:
- label: Apps scope
path: /home/worsch/railiance-apps/SCOPE.md
- label: Container registry docs
path: /home/worsch/railiance-forge/docs/gitea-container-registry.md
spec:
lifecycle: active
environments: [dev, staging, prod]
consumer_service_id: railiance-apps.s5-releases
requires:
capability_type: container-registry
capability_id: railiance-forge.source-forge.container-registry
interface:
type: oci-registry
version_constraint: ">=registry-v2"
auth:
method: api_key
criticality: high
data_classification: confidential
fallback:
mode: none
description: S5 releases require a reachable container registry for private or internal app images.

View File

@@ -0,0 +1,30 @@
apiVersion: railiance.fabric/v1alpha1
kind: DependencyDeclaration
metadata:
id: railiance-enablement.delivery-templates.needs-runner-substrate
name: Enablement runner substrate dependency
owner: railiance-enablement
repo: railiance-enablement
domain: railiance
source_links:
- label: Enablement scope
path: /home/worsch/railiance-enablement/SCOPE.md
- label: Runner ownership contract
path: /home/worsch/railiance-forge/docs/ci-runner-actions-gitops-ownership.md
spec:
lifecycle: planned
environments: [dev, staging, prod]
consumer_service_id: railiance-enablement.delivery-templates
requires:
capability_type: workflow-runner-substrate
capability_id: railiance-forge.source-forge.workflow-runner-substrate
interface:
type: workflow-runner-label-contract
version_constraint: ">=v1"
auth:
method: none
criticality: high
data_classification: internal
fallback:
mode: manual
description: Reusable templates can remain draft-only until forge publishes runner labels and trust evidence.

View File

@@ -0,0 +1,28 @@
apiVersion: railiance.fabric/v1alpha1
kind: DependencyDeclaration
metadata:
id: railiance-forge.source-forge.needs-kubernetes-runtime
name: Forge Kubernetes runtime dependency
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Forge scope
path: /home/worsch/railiance-forge/SCOPE.md
spec:
lifecycle: active
environments: [dev, staging, prod]
consumer_service_id: railiance-forge.source-forge
requires:
capability_type: kubernetes-runtime
capability_id: railiance-cluster.kubernetes.runtime
interface:
type: kubernetes-api
version_constraint: ">=v1"
auth:
method: kubernetes_service_account
criticality: critical
data_classification: restricted
fallback:
mode: none
description: The forge runtime cannot operate without the Railiance Kubernetes runtime.

View File

@@ -0,0 +1,30 @@
apiVersion: railiance.fabric/v1alpha1
kind: DependencyDeclaration
metadata:
id: railiance-forge.source-forge.needs-object-storage
name: Forge object storage dependency
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Backup and restore handoff
path: /home/worsch/railiance-forge/docs/backup-restore-secret-handoff.md
- label: Platform OpenBao object-storage handoff
path: /home/worsch/railiance-platform/docs/openbao.md
spec:
lifecycle: planned
environments: [dev, staging, prod]
consumer_service_id: railiance-forge.source-forge
requires:
capability_type: object-storage
capability_id: artifact-store.object-storage
interface:
type: object-storage-bucket
version_constraint: ">=v1"
auth:
method: sts_token
criticality: high
data_classification: confidential
fallback:
mode: manual
description: Current Gitea package blobs remain on PVC until durable object-storage backup or artifact preservation is proven.

View File

@@ -0,0 +1,28 @@
apiVersion: railiance.fabric/v1alpha1
kind: DependencyDeclaration
metadata:
id: railiance-forge.source-forge.needs-postgresql
name: Forge PostgreSQL dependency
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Backup and restore handoff
path: /home/worsch/railiance-forge/docs/backup-restore-secret-handoff.md
spec:
lifecycle: active
environments: [dev, staging, prod]
consumer_service_id: railiance-forge.source-forge
requires:
capability_type: postgresql-database-service
capability_id: railiance-platform.cnpg.postgresql
interface:
type: database-connection
version_constraint: ">=v16"
auth:
method: database_role
criticality: critical
data_classification: confidential
fallback:
mode: none
description: The forge runtime requires the Gitea database state and cannot degrade safely without it.

View File

@@ -0,0 +1,28 @@
apiVersion: railiance.fabric/v1alpha1
kind: DependencyDeclaration
metadata:
id: railiance-forge.source-forge.needs-runtime-secrets
name: Forge runtime secrets dependency
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Backup and restore handoff
path: /home/worsch/railiance-forge/docs/backup-restore-secret-handoff.md
spec:
lifecycle: active
environments: [dev, staging, prod]
consumer_service_id: railiance-forge.source-forge
requires:
capability_type: runtime-secrets
capability_id: railiance-platform.openbao.runtime-secrets
interface:
type: openbao-kv-v2-mount
version_constraint: ">=v1 <v2"
auth:
method: kubernetes_service_account
criticality: critical
data_classification: secret
fallback:
mode: manual
description: SOPS/age bootstrap can carry encrypted deploy input, but runtime secret custody belongs to the platform path.

View File

@@ -0,0 +1,23 @@
apiVersion: railiance.fabric/v1alpha1
kind: InterfaceDeclaration
metadata:
id: railiance-cluster.kubernetes.api
name: Kubernetes API
owner: railiance-cluster
repo: railiance-cluster
domain: railiance
source_links:
- label: Cluster scope
path: /home/worsch/railiance-cluster/SCOPE.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: Kubernetes API surface and RBAC-controlled runtime contract consumed by Railiance workloads and operators.
interface_type: kubernetes-api
version: v1
service_id: railiance-cluster.kubernetes
capability_ids:
- railiance-cluster.kubernetes.runtime
auth:
method: kubernetes_service_account
data_classification: restricted

View File

@@ -0,0 +1,23 @@
apiVersion: railiance.fabric/v1alpha1
kind: InterfaceDeclaration
metadata:
id: railiance-enablement.delivery-templates.workflow-template-contract
name: Workflow template contract
owner: railiance-enablement
repo: railiance-enablement
domain: railiance
source_links:
- label: Enablement scope
path: /home/worsch/railiance-enablement/SCOPE.md
spec:
lifecycle: planned
environments: [dev, staging, prod]
description: Template contract for reusable Railiance CI/CD and GitOps workflow patterns.
interface_type: workflow-template-contract
version: v1
service_id: railiance-enablement.delivery-templates
capability_ids:
- railiance-enablement.delivery-templates.ci-cd-templates
auth:
method: none
data_classification: internal

View File

@@ -0,0 +1,23 @@
apiVersion: railiance.fabric/v1alpha1
kind: InterfaceDeclaration
metadata:
id: railiance-forge.source-forge.evidence-contract
name: Forge evidence contract
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Observability and evidence contract
path: /home/worsch/railiance-forge/docs/observability-operating-evidence.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: Release-readiness, artifact promotion, restore, storage, and operating evidence contract for forge consumers.
interface_type: evidence-contract
version: v1
service_id: railiance-forge.source-forge
capability_ids:
- railiance-forge.source-forge.artifact-promotion-evidence
auth:
method: none
data_classification: internal

View File

@@ -0,0 +1,25 @@
apiVersion: railiance.fabric/v1alpha1
kind: InterfaceDeclaration
metadata:
id: railiance-forge.source-forge.git-ssh
name: Git SSH endpoint
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Observability and evidence contract
path: /home/worsch/railiance-forge/docs/observability-operating-evidence.md
spec:
lifecycle: planned
environments: [dev, staging, prod]
description: Git-over-SSH endpoint contract for repository clone, fetch, and push operations when exposed.
interface_type: git-ssh
version: gitea-current
service_id: railiance-forge.source-forge
capability_ids:
- railiance-forge.source-forge.source-hosting
endpoint:
notes: Record the published SSH host and port once the endpoint is verified.
auth:
method: static_secret
data_classification: confidential

View File

@@ -0,0 +1,28 @@
apiVersion: railiance.fabric/v1alpha1
kind: InterfaceDeclaration
metadata:
id: railiance-forge.source-forge.oci-registry
name: Gitea OCI registry
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Container registry docs
path: /home/worsch/railiance-forge/docs/gitea-container-registry.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: OCI registry endpoint served by current Gitea for Railiance container images.
interface_type: oci-registry
version: registry-v2
service_id: railiance-forge.source-forge
capability_ids:
- railiance-forge.source-forge.container-registry
endpoint:
url: https://gitea.coulomb.social/v2/
auth:
method: api_key
scopes:
- package:read
- package:write
data_classification: confidential

View File

@@ -0,0 +1,28 @@
apiVersion: railiance.fabric/v1alpha1
kind: InterfaceDeclaration
metadata:
id: railiance-forge.source-forge.python-package-index
name: Gitea Python package index
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Package registry docs
path: /home/worsch/railiance-forge/docs/gitea-package-registry.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: Python package index endpoint served by current Gitea for internal Railiance packages.
interface_type: python-package-index
version: simple-api
service_id: railiance-forge.source-forge
capability_ids:
- railiance-forge.source-forge.python-package-registry
endpoint:
url: https://gitea.coulomb.social/api/packages/coulomb/pypi/simple/
auth:
method: api_key
scopes:
- package:read
- package:write
data_classification: confidential

View File

@@ -0,0 +1,23 @@
apiVersion: railiance.fabric/v1alpha1
kind: InterfaceDeclaration
metadata:
id: railiance-forge.source-forge.runner-label-contract
name: Runner label contract
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Runner ownership contract
path: /home/worsch/railiance-forge/docs/ci-runner-actions-gitops-ownership.md
spec:
lifecycle: planned
environments: [dev, staging, prod]
description: Semantic runner labels, placement, trust levels, and credential boundaries consumed by workflow templates and release checks.
interface_type: workflow-runner-label-contract
version: v1
service_id: railiance-forge.source-forge
capability_ids:
- railiance-forge.source-forge.workflow-runner-substrate
auth:
method: none
data_classification: internal

View File

@@ -0,0 +1,25 @@
apiVersion: railiance.fabric/v1alpha1
kind: InterfaceDeclaration
metadata:
id: railiance-forge.source-forge.web-ui
name: Source forge web UI
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Observability and evidence contract
path: /home/worsch/railiance-forge/docs/observability-operating-evidence.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: Current Gitea web UI and HTTP endpoint for source hosting and package workflows.
interface_type: web-ui
version: gitea-current
service_id: railiance-forge.source-forge
capability_ids:
- railiance-forge.source-forge.source-hosting
endpoint:
url: https://gitea.coulomb.social/
auth:
method: unknown
data_classification: confidential

View File

@@ -0,0 +1,18 @@
apiVersion: railiance.fabric/v1alpha1
kind: ServiceDeclaration
metadata:
id: railiance-apps.s5-releases
name: Railiance S5 app releases
owner: railiance-apps
repo: railiance-apps
domain: railiance
source_links:
- label: Apps scope
path: /home/worsch/railiance-apps/SCOPE.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: S5 application release surface that consumes forge artifacts, app manifests, runbooks, dry-runs, and smoke evidence.
service_type: app-release-surface
provides_capabilities: []
exposes_interfaces: []

View File

@@ -0,0 +1,20 @@
apiVersion: railiance.fabric/v1alpha1
kind: ServiceDeclaration
metadata:
id: railiance-cluster.kubernetes
name: Railiance Kubernetes runtime
owner: railiance-cluster
repo: railiance-cluster
domain: railiance
source_links:
- label: Cluster scope
path: /home/worsch/railiance-cluster/SCOPE.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: Kubernetes runtime layer that provides the API server, namespaces, workloads, Services, Ingresses, and controller substrate for Railiance services.
service_type: cluster-runtime
provides_capabilities:
- railiance-cluster.kubernetes.runtime
exposes_interfaces:
- railiance-cluster.kubernetes.api

View File

@@ -0,0 +1,22 @@
apiVersion: railiance.fabric/v1alpha1
kind: ServiceDeclaration
metadata:
id: railiance-enablement.delivery-templates
name: Railiance delivery templates
owner: railiance-enablement
repo: railiance-enablement
domain: railiance
source_links:
- label: Enablement scope
path: /home/worsch/railiance-enablement/SCOPE.md
- label: Enablement intent
path: /home/worsch/railiance-enablement/INTENT.md
spec:
lifecycle: planned
environments: [dev, staging, prod]
description: Reusable CI/CD and GitOps workflow template surface for Railiance workload delivery.
service_type: enablement-template-surface
provides_capabilities:
- railiance-enablement.delivery-templates.ci-cd-templates
exposes_interfaces:
- railiance-enablement.delivery-templates.workflow-template-contract

View File

@@ -0,0 +1,31 @@
apiVersion: railiance.fabric/v1alpha1
kind: ServiceDeclaration
metadata:
id: railiance-forge.source-forge
name: Railiance source forge
owner: railiance-forge
repo: railiance-forge
domain: railiance
source_links:
- label: Forge scope
path: /home/worsch/railiance-forge/SCOPE.md
- label: Forge intent
path: /home/worsch/railiance-forge/INTENT.md
spec:
lifecycle: active
environments: [dev, staging, prod]
description: Current Gitea source forge and future Forgejo migration surface for source hosting, registries, runner substrate, and release artifact evidence.
service_type: forge-runtime
provides_capabilities:
- railiance-forge.source-forge.source-hosting
- railiance-forge.source-forge.container-registry
- railiance-forge.source-forge.python-package-registry
- railiance-forge.source-forge.workflow-runner-substrate
- railiance-forge.source-forge.artifact-promotion-evidence
exposes_interfaces:
- railiance-forge.source-forge.web-ui
- railiance-forge.source-forge.git-ssh
- railiance-forge.source-forge.oci-registry
- railiance-forge.source-forge.python-package-index
- railiance-forge.source-forge.runner-label-contract
- railiance-forge.source-forge.evidence-contract

File diff suppressed because it is too large Load Diff

View File

@@ -332,6 +332,7 @@ def resolve_zones(
edge_records,
enabled_definitions,
seed_node_ids_by_zone_id,
diagnostics,
)
for candidate in attraction_candidates:
candidates_by_node_id[candidate.node_id].append(candidate)
@@ -400,12 +401,24 @@ def resolve_zones(
internal_edge_ids_by_zone_id: dict[str, list[str]] = defaultdict(list)
boundary_edge_ids_by_zone_id: dict[str, list[str]] = defaultdict(list)
for edge in edge_records:
if _is_context_only_edge(edge):
continue
source_zone_id = assignments.get(edge.source).zone_id if edge.source in assignments else None
target_zone_id = assignments.get(edge.target).zone_id if edge.target in assignments else None
if source_zone_id and source_zone_id == target_zone_id:
internal_edge_ids_by_zone_id[source_zone_id].append(edge.id)
continue
if source_zone_id or target_zone_id:
zone_ids = tuple(sorted(str(zone_id) for zone_id in {source_zone_id, target_zone_id} - {None}))
diagnostics.append(
ZoneDiagnostic(
severity="INFO",
code="ZONE_EDGE_CROSSES_ZONE_BOUNDARY",
message=f"Edge {edge.id} crosses a zone boundary.",
edge_id=edge.id,
zone_ids=zone_ids,
)
)
boundary_edges.append(
ZoneBoundaryEdge(
edge_id=edge.id,
@@ -468,14 +481,18 @@ def _attraction_candidates(
edge_records: tuple[_EdgeRecord, ...],
enabled_definitions: tuple[tuple[int, ZoneDefinition], ...],
seed_node_ids_by_zone_id: Mapping[str, set[str]],
diagnostics: list[ZoneDiagnostic],
) -> list[_Candidate]:
nodes_by_id = {node.id: node for node in node_records}
adjacency: dict[str, list[_EdgeRecord]] = defaultdict(list)
for edge in edge_records:
if _is_context_only_edge(edge):
continue
adjacency[edge.source].append(edge)
adjacency[edge.target].append(edge)
candidates: dict[tuple[str, str], _Candidate] = {}
depth_limit_diagnostics: set[tuple[str, str]] = set()
for definition_order, definition in enabled_definitions:
seed_node_ids = seed_node_ids_by_zone_id.get(definition.id, set())
if not seed_node_ids:
@@ -486,6 +503,27 @@ def _attraction_candidates(
while queue:
node_id, depth = queue.popleft()
if depth >= rule.depth:
if _has_matching_attraction_neighbor(
node_id,
adjacency.get(node_id, []),
nodes_by_id,
rule,
):
key = (definition.id, node_id)
if key not in depth_limit_diagnostics:
depth_limit_diagnostics.add(key)
diagnostics.append(
ZoneDiagnostic(
severity="INFO",
code="ZONE_ATTRACTION_DEPTH_LIMIT_REACHED",
message=(
f"Zone {definition.id} reached attraction depth "
f"{rule.depth} at node {node_id}."
),
node_id=node_id,
zone_ids=(definition.id,),
)
)
continue
for edge in adjacency.get(node_id, []):
if not _edge_matches_attraction_rule(edge, rule):
@@ -521,6 +559,24 @@ def _attraction_candidates(
return sorted(candidates.values(), key=lambda candidate: (candidate.node_id, candidate.zone_id))
def _has_matching_attraction_neighbor(
node_id: str,
edges: Iterable[_EdgeRecord],
nodes_by_id: Mapping[str, _NodeRecord],
rule: ZoneAttractionRule,
) -> bool:
for edge in edges:
if not _edge_matches_attraction_rule(edge, rule):
continue
neighbor_id = _neighbor_for_direction(node_id, edge, rule.direction)
if not neighbor_id:
continue
neighbor = nodes_by_id.get(neighbor_id)
if neighbor and _rule_matches(neighbor.data, rule.node_filter, empty_matches=True):
return True
return False
def _node_records(nodes: Iterable[Mapping[str, Any]]) -> tuple[_NodeRecord, ...]:
records: list[_NodeRecord] = []
for order, element in enumerate(nodes):
@@ -567,6 +623,14 @@ def _edge_matches_attraction_rule(edge: _EdgeRecord, rule: ZoneAttractionRule) -
return _rule_matches(edge.data, rule.edge_filter, empty_matches=True)
def _is_context_only_edge(edge: _EdgeRecord) -> bool:
return _trueish(edge.data.get("displayOnly", edge.data.get("display_only"))) or edge.edge_type == "declares"
def _trueish(value: Any) -> bool:
return value is True or str(value).lower() == "true"
def _neighbor_for_direction(node_id: str, edge: _EdgeRecord, direction: str) -> str:
if direction in {"out", "both"} and edge.source == node_id:
return edge.target

View File

View File

@@ -0,0 +1,122 @@
---
id: capability.railiance.fabric-graph
name: Railiance Fabric Ecosystem Graph
summary: 'Models the durable infrastructure-responsibility graph of the Railiance netkingdom: schemas,
discovery tools, registry services, graph queries, and State Hub export contracts for services, machines,
repos, deployables, endpoints, ownership, dependencies, and bindings.'
owner: railiance-fabric
status: draft
domain: financials
tags:
- railiance
- graph
- ownership
- discovery
maturity:
discovery:
current: D3
target: D5
confidence: medium
rationale: README and SCOPE.md document the ecosystem graph model bounded by financial/operational
accountability (who pays, who is accountable), with king/lord/tenant ownership concepts referenced
in docs/FabricDiscoveryAndUpdate.md.
availability:
current: A1
target: A3
confidence: medium
rationale: Python package (`railiance-fabric`) providing a declaration loader and validator; consumed
as a library, no hosted service documented yet.
external_evidence:
completeness:
level: C1
confidence: low
basis: scope_vs_intent_and_consumer_expectations
satisfied_expectations:
- ecosystem graph declaration loader and validator
- schemas for services/machines/repos/deployables/endpoints/ownership/dependencies/bindings
broken_expectations: []
out_of_scope_expectations: []
reliability:
level: R0
confidence: low
basis: consumer_quality_signals
known_reliability_risks:
- discovery/rebuild/update-loop architecture documented as still evolving per docs/FabricDiscoveryAndUpdate.md
discovery:
intent: Let repos declare services, capabilities, interfaces, dependencies, and bindings in source-controlled
files, and model the resulting durable infrastructure-responsibility graph across the Railiance ecosystem.
includes:
- ecosystem graph schema and declaration loader/validator
- State Hub export contracts for the graph
excludes:
- actual infrastructure provisioning (see railiance-infra, railiance-cluster)
assumptions: []
use_cases: []
research_memos: []
availability:
current_level: A1
target_level: A3
current_artifacts:
- Python package (`railiance-fabric`)
target_artifacts: []
consumption_modes:
- library import
- cli (validation)
relations:
depends_on: []
supports: []
related_to: []
evidence:
documentation:
- README.md
- SCOPE.md
- docs/FabricDiscoveryAndUpdate.md
tests:
- tests/
consumer_feedback: []
bug_reports: []
incidents: []
consumer_guidance:
recommended_for:
- Railiance repos wanting to declare their place in the ecosystem ownership/dependency graph
not_recommended_for:
- needs for actual infrastructure provisioning (see railiance-infra/-cluster)
known_limitations:
- discovery/rebuild/update-loop architecture still evolving
promotion_history: []
---
# Railiance Fabric Ecosystem Graph
## Overview
`railiance-fabric` models the durable infrastructure-responsibility graph of the Railiance netkingdom — who pays for infrastructure, who is accountable for it, and which durable interfaces create value across boundaries — via schemas, a declaration loader/validator, and State Hub export contracts.
## Assessment notes
### Discovery
README and SCOPE.md document the ecosystem graph model bounded by financial/operational accountability (who pays, who is accountable), with king/lord/tenant ownership concepts referenced in docs/FabricDiscoveryAndUpdate.md.
### Availability
Python package (`railiance-fabric`) providing a declaration loader and validator; consumed as a library, no hosted service documented yet.
### Completeness
First-pass honest assessment from the REUSE-WP-0017 coverage campaign
(reuse-surface). No external consumer feedback exists yet; levels reflect
scope-vs-intent documentation quality, not internal code quality.
### Reliability
No production consumer telemetry exists yet; reliability level is
intentionally conservative pending REUSE-WP-0019 reuse-telemetry evidence.
## Promotion checklist
- [x] ID follows `capability.<domain>.<name>` pattern
- [x] Maturity enums match `specs/CapabilityMaturityStandard.md`
- [x] `external_evidence` is populated separately from `maturity`
- [ ] Relations reference valid capability IDs (none yet)
- [x] Index entry added in `registry/indexes/capabilities.yaml`

View File

@@ -0,0 +1,22 @@
version: 1
updated: '2026-07-06'
domain: helix_forge
capabilities:
- id: capability.railiance.fabric-graph
name: Railiance Fabric Ecosystem Graph
summary: 'Models the durable infrastructure-responsibility graph of the Railiance netkingdom: schemas,
discovery tools, registry services, graph queries, and State Hub export contracts for services, machines,
repos, deployables, endpoints, ownership, dependencies, and bindings.'
vector: D3 / A1 / C1 / R0
domain: financials
status: draft
owner: railiance-fabric
path: registry/capabilities/capability.railiance.fabric-graph.md
tags:
- railiance
- graph
- ownership
- discovery
consumption_modes:
- library import
- cli (validation)

View File

@@ -402,6 +402,7 @@ def test_registry_serves_graph_explorer_exports(tmp_path: Path) -> None:
assert 'id="zone-overlay"' in page
assert 'id="zone-boundary-toggle"' in page
assert 'id="zone-group-select"' in page
assert 'id="zone-layout-select"' in page
assert 'id="node-type-filter"' in page
assert 'id="edge-type-filter"' in page
assert 'id="rule-panel"' in page
@@ -415,6 +416,49 @@ def test_registry_serves_graph_explorer_exports(tmp_path: Path) -> None:
assert "ruleRemovalSignature" in page
assert "zoneModeFields" in page
assert "zoneForData" in page
assert "defaultZoneDefinitions" in page
assert "resolveZoneInstances" in page
assert "zoneDiagnosticCodes" in page
assert "ZONE_EMPTY_SEED_SET" in page
assert "ZONE_NODE_SEEDED_BY_MULTIPLE_ZONES" in page
assert "ZONE_EDGE_CROSSES_ZONE_BOUNDARY" in page
assert "zone.diagnostics" in page
assert "isZoneContextOnlyEdge" in page
assert "isZoneConnectivityEdge" in page
assert "currentZoneViewState" in page
assert "normalizeZoneViewState" in page
assert "zoneDefinitionSet" in page
assert "zoneDefinitionSets" in page
assert "fabric-default" in page
assert "activeZoneLayoutAlgorithm" in page
assert "zoneLayoutAlgorithms" in page
assert "normalizeZoneLayoutAlgorithm" in page
assert "zoneLayoutAlgorithm" in page
assert "zoneLayout" in page
assert "compact-grid" in page
assert "circle" in page
assert "zoneContainerState" in page
assert "ensureZoneContainer" in page
assert "packZoneContainers" in page
assert "applyZoneContainerLayout" in page
assert "layoutZoneSubgraph" in page
assert "serializedZoneContainers" in page
assert "normalizedZoneContainers" in page
assert "collapsedZoneSnapshots" in page
assert "zoneDragState" in page
assert "startZoneDrag" in page
assert "moveZoneDrag" in page
assert "finishZoneDrag" in page
assert "Moved zone" in page
assert "cursor: grab" in page
assert "background: transparent" in page
assert "box-shadow: none" in page
assert "collapseZone" in page
assert "expandZone" in page
assert "zoneCollapseNodeId" in page
assert "Collapse Zone" in page
assert "Expand Zone" in page
assert 'normalize: "deploymentEnvironment"' in page
assert "zoneBoundsForNodes" in page
assert "renderZoneOverlay" in page
assert "renderZoneDetails" in page

View File

@@ -91,6 +91,46 @@ def test_resolver_assigns_seed_nodes_and_boundary_edges() -> None:
assert resolution.boundary_edges[0].edge_id == "edge.prod-test"
assert resolution.boundary_edges[0].source_zone_id == "prod"
assert resolution.boundary_edges[0].target_zone_id == "test"
assert "ZONE_EDGE_CROSSES_ZONE_BOUNDARY" in {
diagnostic.code for diagnostic in resolution.diagnostics
}
def test_resolver_ignores_context_only_edges_for_boundaries_and_attraction() -> None:
resolution = resolve_zones(
nodes=[
_node("repo", kind="Repository"),
_node("svc.prod", deploymentEnvironment="prod"),
_node("svc.context", kind="service"),
],
edges=[
_edge("edge.repo-prod", "repo", "svc.prod", "declares", displayOnly=True),
_edge("edge.prod-context", "svc.prod", "svc.context", "declares", displayOnly=True),
],
zone_definitions=[
{
"id": "prod",
"label": "prod",
"membership": {"field": "deploymentEnvironment", "op": "equals", "value": "prod"},
"attraction": {
"rules": [
{
"edge_type": "*",
"direction": "both",
"depth": 1,
}
]
},
},
],
)
assert resolution.zone_by_id("prod").boundary_edge_ids == ()
assert resolution.zone_by_id("prod").internal_edge_ids == ()
assert "svc.context" not in resolution.node_assignments
assert "ZONE_EDGE_CROSSES_ZONE_BOUNDARY" not in {
diagnostic.code for diagnostic in resolution.diagnostics
}
def test_resolver_attracts_nodes_by_edge_type_direction_and_depth() -> None:
@@ -128,6 +168,9 @@ def test_resolver_attracts_nodes_by_edge_type_direction_and_depth() -> None:
assert "far" not in resolution.node_assignments
assert resolution.zone_by_id("prod").internal_edge_ids == ("edge.seed-near",)
assert resolution.zone_by_id("prod").boundary_edge_ids == ("edge.near-far",)
assert "ZONE_ATTRACTION_DEPTH_LIMIT_REACHED" in {
diagnostic.code for diagnostic in resolution.diagnostics
}
def test_resolver_keeps_seed_membership_over_attraction() -> None:
@@ -229,3 +272,19 @@ def test_resolver_serializes_resolution() -> None:
assert serialized["zones"][0]["id"] == "prod"
assert serialized["node_assignments"]["svc"]["zone_id"] == "prod"
assert serialized["node_assignments"]["svc"]["reason"] == "seed"
def test_resolver_reports_empty_zone_seed_set() -> None:
resolution = resolve_zones(
nodes=[_node("svc", deploymentEnvironment="dev")],
edges=[],
zone_definitions=[
{
"id": "prod",
"membership": {"field": "deploymentEnvironment", "op": "equals", "value": "prod"},
}
],
)
assert resolution.zone_by_id("prod").node_ids == ()
assert "ZONE_EMPTY_SEED_SET" in {diagnostic.code for diagnostic in resolution.diagnostics}

View File

@@ -0,0 +1,46 @@
---
id: ADHOC-2026-05-25
type: workplan
title: "Ad Hoc Fixes 2026-05-25"
domain: railiance
repo: railiance-fabric
status: finished
owner: codex
topic_slug: railiance
created: "2026-05-25"
updated: "2026-05-25"
state_hub_workstream_id: "77e80432-9548-4ac8-9654-7beb931741e4"
---
# ADHOC-2026-05-25 - Ad Hoc Fixes
## Add Zone Layout Algorithm Control
```task
id: ADHOC-2026-05-25-T01
status: done
priority: medium
state_hub_task_id: "f0b4fdfa-9c26-4f8a-9372-90242eeec5d8"
```
The graph explorer now lays zone subgraphs out as a grid inside each zone
container. Add an operator-facing control that can switch the zone-local layout
algorithm while keeping stable zone containers intact.
Expected result: the map controls expose a zone layout selector, the selected
algorithm applies to each zone subgraph, and the setting persists in saved or
copied view state.
Result: Added a `Zone Layout` selector with Grid and Circle algorithms. The
selected algorithm is stored in nested zone view state, reflected by the
`zoneLayout` URL alias for non-default layout, and reapplies zone-local node
placement without moving stable zone containers.
Verification:
- `python3 -m pytest tests/test_graph_explorer.py tests/test_zone_view.py -q`
passed.
- Generated graph explorer JavaScript passed `node --check`.
- `python3 -m railiance_fabric.cli validate .` passed.
- `python3 -m pytest -q` passed with 72 tests.
- Headless Edge screenshots confirmed Grid and Circle zone layouts render.

View File

@@ -0,0 +1,46 @@
---
id: ADHOC-2026-06-03
type: workplan
title: "Ad Hoc Fixes 2026-06-03"
domain: railiance
repo: railiance-fabric
status: finished
owner: codex
topic_slug: railiance
created: "2026-06-03"
updated: "2026-06-03"
state_hub_workstream_id: "c39b02dd-8074-4efd-ad18-add5595bf646"
---
# ADHOC-2026-06-03 - Ad Hoc Fixes
## Add Graph Explorer Make Target
```task
id: ADHOC-2026-06-03-T01
status: done
priority: medium
state_hub_task_id: "5605e418-95f4-4658-8021-9ee6f00de537"
```
The graph explorer is served by the registry HTTP service, but starting it
currently requires remembering the full registry command and database path.
Add a Makefile target that starts the registry-backed graph explorer from the
repo root with defaults for the local database, host, and port. Calling `make`
without an explicit target should list available targets rather than start a
long-running service. Document the target and available overrides.
Result: Added `make graph-explorer`, with `registry` as an alias, defaulting to
`.railiance-fabric/registry.sqlite3`, `127.0.0.1`, and port `8765`. Plain
`make` now prints the available targets instead of starting the service. The
target uses `python3 -m railiance_fabric.server`, so it works from the checkout
without requiring an installed console script. Updated the README and graph
explorer operations guide with the target and override examples.
Verification:
- Confirmed plain `make` lists available targets.
- Started `make graph-explorer PORT=9877 REGISTRY_DB=/tmp/railiance-fabric-make-test.sqlite3`.
- Confirmed `GET http://127.0.0.1:9877/status` returned `status: ok`.
- Stopped the temporary verification server on port `9877`.

View File

@@ -0,0 +1,34 @@
---
id: ADHOC-2026-06-06
type: workplan
title: "Ad Hoc Fixes 2026-06-06"
domain: railiance
repo: railiance-fabric
status: finished
owner: codex
topic_slug: railiance
created: "2026-06-06"
updated: "2026-06-06"
state_hub_workstream_id: "02426929-e247-4fbf-8072-ea05cac41e93"
---
# ADHOC-2026-06-06 - Ad Hoc Fixes
## Document Semantic Attractors
```task
id: ADHOC-2026-06-06-T01
status: done
priority: medium
state_hub_task_id: "982d1571-128c-40de-bedf-5d70b2ffd586"
```
Refine the concept of semantic attractors for the graph explorer: topic-like
view entities such as `security`, `development`, and `operations` that pull
repositories or other entities based on semantic closeness, initially scored
from repo `SCOPE.md` files and mapped into spring-layout strength.
Result: Added `docs/semantic-attractors.md` with the concept model, SCOPE.md
scoring approach, score semantics, layout mapping, payload shape, operator
workflow, relationship to zones, initial presets, implementation path, and open
questions. Linked the concept from the README and graph explorer contract.

View File

@@ -2,9 +2,9 @@
id: RAIL-FAB-WP-0001
type: workplan
title: "Railiance Ecosystem Graph Model"
domain: railiance
domain: financials
repo: railiance-fabric
status: completed
status: finished
owner: codex
topic_slug: railiance
planning_priority: high

View File

@@ -2,9 +2,9 @@
id: RAIL-FAB-WP-0002
type: workplan
title: "Railiance Ecosystem Registry Service"
domain: railiance
domain: financials
repo: railiance-fabric
status: completed
status: finished
owner: codex
topic_slug: railiance
planning_priority: high

View File

@@ -2,9 +2,9 @@
id: RAIL-FAB-WP-0003
type: workplan
title: "Registry Feed And Library Inventory"
domain: railiance
domain: financials
repo: railiance-fabric
status: completed
status: finished
owner: codex
topic_slug: railiance
planning_priority: high

View File

@@ -2,9 +2,9 @@
id: RAIL-FAB-WP-0004
type: workplan
title: "Registry Inventory And Drift Views"
domain: railiance
domain: financials
repo: railiance-fabric
status: completed
status: finished
owner: codex
topic_slug: railiance
planning_priority: high

View File

@@ -2,9 +2,9 @@
id: RAIL-FAB-WP-0005
type: workplan
title: "Registry Hardening"
domain: railiance
domain: financials
repo: railiance-fabric
status: completed
status: finished
owner: codex
topic_slug: railiance
planning_priority: medium

View File

@@ -2,9 +2,9 @@
id: RAIL-FAB-WP-0006
type: workplan
title: "Multi-Repo Registry Onboarding"
domain: railiance
domain: financials
repo: railiance-fabric
status: completed
status: finished
owner: codex
topic_slug: railiance
planning_priority: high

View File

@@ -2,9 +2,9 @@
id: RAIL-FAB-WP-0007
type: workplan
title: "All Local Repo Onboarding"
domain: railiance
domain: financials
repo: railiance-fabric
status: completed
status: finished
owner: codex
topic_slug: railiance
planning_priority: medium

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0008
type: workplan
title: "Interactive Fabric Map"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0009
type: workplan
title: "Graph Explorer UI Refinement"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0010
type: workplan
title: "Repo Reality Scanner"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0011
type: workplan
title: "Operational Rescan Loops"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0012
type: workplan
title: "Baseline Rollout And Conflict Review"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0013
type: workplan
title: "Path Scoped Duplicate Identity"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0014
type: workplan
title: "Runtime Topology Discovery"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0015
type: workplan
title: "Runtime Entity Taxonomy Refinement"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0016
type: workplan
title: "Canon-Aligned Graph Model Reset And Reingest"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0017
type: workplan
title: "Financial Fabric Model Reset"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0018
type: workplan
title: "Accountability Root Discovery And Update Loop"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0019
type: workplan
title: "Duplicate Repository Identity Review"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0020
type: workplan
title: "Deployment Zone Discovery And Visualization"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,7 +2,7 @@
id: RAIL-FAB-WP-0021
type: workplan
title: "Zone Boundary Overlays"
domain: railiance
domain: financials
repo: railiance-fabric
status: finished
owner: codex

View File

@@ -2,11 +2,11 @@
id: RAIL-FAB-WP-0022
type: workplan
title: "Promote graph zones to first-class visualization entities"
domain: railiance
domain: financials
repo: railiance-fabric
status: active
status: finished
owner: codex
topic_slug: railiance-fabric
topic_slug: railiance
created: "2026-05-24"
updated: "2026-05-24"
state_hub_workstream_id: "343f8383-ba5e-4d60-b55e-81611954d9b9"
@@ -95,7 +95,7 @@ summaries, and conflict diagnostics. Covered the core behavior in
```task
id: RAIL-FAB-WP-0022-T03
status: todo
status: done
priority: high
state_hub_task_id: "c89d8d53-72a4-4590-a0e5-67b012c3550c"
```
@@ -114,11 +114,20 @@ The current operator-facing behavior should remain available:
Expected result: existing graph explorer tests continue to pass, with new tests
showing that the UI obtains zone rectangles from resolved zone instances.
Result: Refactored the graph explorer overlay to use explicit default zone
definitions and a client-side `resolveZoneInstances()` path. Deployment
environment zones now resolve through declarative membership rules with
`deploymentEnvironment` normalization for `dev` -> `dev-tegwick`,
`test`/`staging` -> `test`, `prod` -> `prod`, and ignored `all` values. Access
zone overlays are generated as dynamic definitions from visible graph evidence.
The overlay keeps the single-zone visible-node assignment behavior while
preserving edge evidence in zone details.
## Task 4: Add Zone Diagnostics To The Explorer
```task
id: RAIL-FAB-WP-0022-T04
status: todo
status: done
priority: medium
state_hub_task_id: "d140cb5b-6a35-4cb0-ab68-e39e708c08e9"
```
@@ -137,11 +146,17 @@ Diagnostics should include at least:
Expected result: zone detail panels show scoped diagnostics, and tests verify
that diagnostics are generated by the resolver rather than ad hoc UI checks.
Result: Added resolver diagnostics for empty seed sets, overlapping zone
membership, attraction depth-limit stops, and boundary-crossing edges. The graph
explorer now surfaces scoped zone diagnostics in the selected zone detail panel
and orientation context, with assertions proving diagnostics come from the zone
resolver path.
## Task 5: Persist Zone View Settings In Profiles
```task
id: RAIL-FAB-WP-0022-T05
status: todo
status: done
priority: medium
state_hub_task_id: "765caa50-f372-4ab4-adb4-87660e684c54"
```
@@ -158,11 +173,18 @@ At minimum, preserve:
Expected result: saved views restore the same zone mode and default definition
set after reload.
Result: Added explicit nested zone state to graph explorer profiles with
`visible`, `grouping`, `definitionSet`, and `presentation` fields while keeping
legacy URL aliases for `zoneBoundaries`, `zoneGrouping`, and
`zoneDefinitionSet`. Saved and copied views now preserve the active zone
definition set and presentation state, and profile restore normalizes unknown
future definition sets back to the Fabric default.
## Task 6: Prototype Collapse-To-Zone-Node
```task
id: RAIL-FAB-WP-0022-T06
status: todo
status: done
priority: medium
state_hub_task_id: "7f3676cb-3d2e-417c-a385-f95545bcd738"
```
@@ -181,11 +203,18 @@ The prototype should:
Expected result: collapse behavior works for one zone at a time and is covered
by focused tests. Multi-zone hierarchy can remain future work.
Result: Added a view-only zone collapse prototype to the graph explorer. Zone
detail panels now offer `Collapse Zone`; collapsed zones hide member nodes,
render a synthetic zone node with node/internal-edge/boundary-edge summaries,
draw synthetic boundary edges to visible external neighbors, and expose
`Expand Zone` from the collapsed zone node. Expanding removes synthetic elements
and restores the original graph view without changing the underlying payload.
## Task 7: Prepare For Per-Zone Layout
```task
id: RAIL-FAB-WP-0022-T07
status: todo
status: done
priority: low
state_hub_task_id: "4b6f0b7e-a066-490d-8160-ba23b03cf820"
```
@@ -200,6 +229,12 @@ a follow-up workplan for two-phase layout.
Expected result: the codebase has a documented path toward per-zone layouts
without destabilizing the current graph explorer.
Result: Documented the per-zone layout preparation path in
`docs/ZoneEntityVisualization.md`. The recommended direction is a two-phase
layout: resolve zones and containers first, then compute local zone coordinates
and project them into Cytoscape space. The note identifies the prerequisites
already established by WP-0022 and avoids a premature nested-layout rewrite.
## Acceptance Criteria
- Zone entity behavior is documented in `docs/ZoneEntityVisualization.md`.

View File

@@ -0,0 +1,115 @@
---
id: RAIL-FAB-WP-0023
type: workplan
title: "Improve zone labels and dragging"
domain: financials
repo: railiance-fabric
status: finished
owner: codex
topic_slug: railiance
created: "2026-05-25"
updated: "2026-06-05"
state_hub_workstream_id: "f02e14c5-e60f-4950-b1a2-682c38b30431"
---
# Improve Zone Labels And Dragging
## Context
RAIL-FAB-WP-0021 introduced zone boundary rectangles and RAIL-FAB-WP-0022
promoted zones to first-class graph explorer view entities. The current zone
labels still look like small framed buttons with a white background. That makes
the overlay read more like controls than like labels printed on a drawing
surface.
The next interaction step is to let the operator grab a zone and move it around,
dragging all currently attached visible nodes with it. This makes zones behave
more like the intended "piece of paper" view entity while keeping the underlying
Fabric graph unchanged.
## Task 1: Simplify Zone Labels
```task
id: RAIL-FAB-WP-0023-T01
status: done
priority: high
state_hub_task_id: "cb31f964-9e25-483d-b2b3-c4acc7a1033a"
```
Change zone labels from framed button badges to plain text in the upper-left
corner of the zone rectangle.
The label should:
- have no frame;
- have no white background;
- remain readable against the zone fill;
- still be keyboard-focusable/clickable enough to open zone details;
- avoid adding visual clutter to dense graph views.
Expected result: graph explorer zone labels look like text drawn on the zone
surface rather than separate UI controls.
Result: Updated graph explorer zone labels to render as transparent, unframed
text in the upper-left corner of each zone rectangle. Labels remain
keyboard-focusable and clickable, and the visual smoke screenshot confirms the
labels read as text on the zone surface.
## Task 2: Drag Zones With Member Nodes
```task
id: RAIL-FAB-WP-0023-T02
status: done
priority: high
state_hub_task_id: "84de3a0d-2ab9-4775-b026-87646ea14176"
```
Add a zone drag interaction that moves all currently attached visible member
nodes with the zone.
The interaction should:
- start from the zone label or zone boundary affordance;
- move assigned visible nodes by the drag delta;
- keep Cytoscape node positions and overlay bounds in sync;
- update zone details and labels during/after the drag;
- avoid mutating the underlying Fabric payload;
- not interfere with normal node dragging more than necessary.
Expected result: grabbing a zone lets the operator reposition the visible zone
subgraph as a unit.
Result: Added a view-only zone drag interaction using the plain zone label as
the grab handle. Dragging translates the currently assigned visible zone member
nodes by the pointer delta, recomputes overlay bounds, refreshes zone details,
and leaves the Fabric graph payload unchanged.
## Task 3: Verify Interaction Behavior
```task
id: RAIL-FAB-WP-0023-T03
status: done
priority: medium
state_hub_task_id: "8793e982-8991-4cda-8259-3f981bbb9201"
```
Verify the visual and interaction behavior with focused tests and a browser
smoke check.
The verification should cover:
- static UI test assertions for the new label/drag helpers;
- JavaScript syntax validation;
- graph explorer focused tests;
- a visual smoke screenshot showing plain labels;
- manual or scripted confirmation that zone dragging moves member nodes.
Expected result: the UI renders clean labels and the zone drag interaction works
without breaking existing graph explorer behavior.
Result: Static UI assertions, JavaScript syntax validation, focused graph tests,
full test suite, Fabric CLI validation, and a headless Edge visual smoke pass.
The scripted drag smoke ran against the registry-backed graph explorer in
disposable Edge via CDP, dragged the `dev-tegwick` zone label, confirmed 25
rendered nodes moved together, and observed the UI status text
`Moved zone "dev-tegwick".`

View File

@@ -0,0 +1,134 @@
---
id: RAIL-FAB-WP-0024
type: workplan
title: "Stabilize zone containers and layout zone subgraphs"
domain: financials
repo: railiance-fabric
status: finished
owner: codex
topic_slug: railiance
created: "2026-05-25"
updated: "2026-05-25"
state_hub_workstream_id: "63202459-2f73-409a-8881-307a5fc1835a"
---
# Stabilize Zone Containers And Layout Zone Subgraphs
## Context
RAIL-FAB-WP-0022 made zones first-class visualization entities and
RAIL-FAB-WP-0023 added plain labels plus view-only zone dragging. The current
prototype still derives a zone rectangle directly from the current positions of
its member nodes. When the operator changes the layout algorithm or reruns
layout, the zone surface moves with the global graph layout instead of staying
where the operator placed it.
The current resolver also treats every edge attached to a zoned node as zone
context. That includes display-only repository declaration edges. Those edges
help explain where graph declarations came from, but they should not be read as
direct deployment or operational connections across a zone boundary.
This workplan moves the graph explorer toward the intended model: a zone is a
stable drawing surface, and the assigned subgraph is laid out inside that
surface as a separate view concern.
## Task 1: Separate Context Edges From Zone Boundary Connectivity
```task
id: RAIL-FAB-WP-0024-T01
status: done
priority: high
state_hub_task_id: "5e018a70-5aff-41bb-b0f9-0f59302c58ae"
```
Exclude display-only/context edges, especially repository `declares` edges,
from zone boundary diagnostics and collapsed-zone boundary edges.
Expected result: zone detail may still mention contextual evidence when useful,
but display-only declaration edges do not make it look as if every zoned node is
directly connected to an unzoned repository.
Result: Display-only edges and repository `declares` edges are now treated as
context-only in both the shared zone resolver and the browser view. They do not
create boundary diagnostics, attraction paths, or collapsed-zone boundary
edges.
## Task 2: Persist Stable Zone Container Positions
```task
id: RAIL-FAB-WP-0024-T02
status: done
priority: high
state_hub_task_id: "ffa3f7b8-ee85-461a-89b8-007e4879171c"
```
Introduce a view-level zone container state keyed by stable zone id.
The implementation should:
- remember zone container center and size after layout and drag;
- keep user-moved zone positions stable when the global layout algorithm
changes;
- keep saved/copied view state compatible with the nested `zone` object;
- avoid mutating the Fabric graph payload.
Expected result: switching between layout algorithms keeps zone papers in the
same operator-chosen positions.
Result: The graph explorer now stores stable zone containers in view state.
Containers remember graph-coordinate position and size, survive global layout
reruns, can be saved/copied through the nested `zone` state, and remain separate
from Fabric graph payload data.
## Task 3: Layout Zone Subgraphs Inside Containers
```task
id: RAIL-FAB-WP-0024-T03
status: done
priority: high
state_hub_task_id: "f2f5adfa-4de4-4606-aa9f-51dbf10c6443"
```
Add a per-zone layout pass that positions assigned visible nodes inside their
zone container after the global layout places the surrounding graph.
The first implementation may use a deterministic compact layout rather than a
full nested Cytoscape layout, as long as it:
- only moves visible nodes assigned to the zone;
- keeps each node inside the zone's drawing surface;
- treats unzoned nodes as part of the base canvas;
- keeps edge routing intact through Cytoscape's normal renderer.
Expected result: the visible subgraph inside each zone is arranged by the zone
view model, not merely enclosed after the global layout.
Result: After global layout, each visible zone projects its assigned nodes into
a local compact layout inside its stable container. New, not-yet-moved zones are
packed into readable rows so the default deployment-environment papers start as
separate drawing surfaces.
## Task 4: Verify And Document Zone Layout Semantics
```task
id: RAIL-FAB-WP-0024-T04
status: done
priority: medium
state_hub_task_id: "cd418134-cacc-42f6-a6ea-0bfd1cda9965"
```
Update the graph explorer contract and run focused validation.
Verification should cover:
- static UI assertions for context-edge filtering and zone container helpers;
- JavaScript syntax validation;
- focused graph explorer and zone resolver tests;
- a visual smoke check of the graph explorer.
Expected result: documentation and tests describe the new semantics, and the
running UI shows stable zone containers with locally arranged member nodes.
Result: Updated the graph explorer contract and zone entity documentation.
Focused tests, generated JavaScript syntax validation, full tests, CLI
validation, and a headless Edge visual smoke check all passed.