capture #49a: classification taxonomy + per-wing/repo tagging (I1 prerequisite) #50

Closed
opened 2026-06-22 20:26:32 +00:00 by mathias · 1 comment
Owner

Parent: #49 · Spec: specs/capture-bdd-spec.md §4.1 · Blocks the I1 gate in: #49d, #49f

Scope

Define the data-classification taxonomy and the per-wing / per-repo tagging mechanism the capture server reads to enforce I1. Pure prerequisite — no code dependency on the other sub-issues; can start immediately.

Per spec decision §4.1 (model C), the server must independently derive a target's classification to cross-check the caller's declared value (stricter wins). That derivation needs a tag to read. This issue provides it.

What to build

  1. Taxonomy — the ordered sensitivity levels. Proposed: public < internal < confidential (ordered so "stricter wins" is a simple max). Confirm/adjust against the sovereignty model in infra/docs/architecture/01-invariants.md (I1) and the trust zones (sovereign-soil / external-metered / us-nexus) — the classification must map cleanly onto placement rules.
  2. Per-wing tag (brain) — a way to tag a brain wing's classification (e.g. frontmatter on a wing _index.md, or a wing-classification.yaml the server reads). A client-* wing defaults to confidential; hyperguild/homelab default to internal; explicitly-public wings to public.
  3. Per-repo tag (gitea) — classification for a Gitea repo target (repo topic, a .classification file, or a server-side map). Same defaulting logic.
  4. Derivation functionderiveClassification(target) -> level the use-case calls. Unknown/untagged target fails safe to the strictest (confidential), never to permissive.

Acceptance criteria

  • Taxonomy levels defined + ordered; documented (brain note + referenced from the spec)
  • Per-wing classification tag mechanism implemented and readable by the server
  • Per-repo classification tag mechanism implemented and readable by the server
  • deriveClassification returns the level for a tagged target; untagged → confidential (fail safe)
  • Defaulting rules applied (client-* → confidential; homelab/hyperguild → internal)
  • Unit tests incl. the untagged-fails-safe path
  • task check green

Notes

This is the load-bearing prerequisite: until it exists, the I1 sovereignty gate (#49d) and the Q4 classification-aware audit posture (#49f) are not enforceable. Fail-safe-to-strictest is the critical correctness property — a missing tag must never silently downgrade.

**Parent:** #49 · **Spec:** `specs/capture-bdd-spec.md` §4.1 · **Blocks the I1 gate in:** #49d, #49f ## Scope Define the data-classification taxonomy and the per-wing / per-repo tagging mechanism the capture server reads to enforce I1. Pure prerequisite — no code dependency on the other sub-issues; can start immediately. Per spec decision §4.1 (model C), the server must independently derive a target's classification to cross-check the caller's declared value (stricter wins). That derivation needs a tag to read. This issue provides it. ## What to build 1. **Taxonomy** — the ordered sensitivity levels. Proposed: `public` < `internal` < `confidential` (ordered so "stricter wins" is a simple max). Confirm/adjust against the sovereignty model in `infra/docs/architecture/01-invariants.md` (I1) and the trust zones (sovereign-soil / external-metered / us-nexus) — the classification must map cleanly onto placement rules. 2. **Per-wing tag (brain)** — a way to tag a brain wing's classification (e.g. frontmatter on a wing `_index.md`, or a `wing-classification.yaml` the server reads). A `client-*` wing defaults to `confidential`; `hyperguild`/`homelab` default to `internal`; explicitly-public wings to `public`. 3. **Per-repo tag (gitea)** — classification for a Gitea repo target (repo topic, a `.classification` file, or a server-side map). Same defaulting logic. 4. **Derivation function** — `deriveClassification(target) -> level` the use-case calls. Unknown/untagged target **fails safe to the strictest** (`confidential`), never to permissive. ## Acceptance criteria - [ ] Taxonomy levels defined + ordered; documented (brain note + referenced from the spec) - [ ] Per-wing classification tag mechanism implemented and readable by the server - [ ] Per-repo classification tag mechanism implemented and readable by the server - [ ] `deriveClassification` returns the level for a tagged target; **untagged → confidential (fail safe)** - [ ] Defaulting rules applied (`client-*` → confidential; homelab/hyperguild → internal) - [ ] Unit tests incl. the untagged-fails-safe path - [ ] `task check` green ## Notes This is the load-bearing prerequisite: until it exists, the I1 sovereignty gate (#49d) and the Q4 classification-aware audit posture (#49f) are not enforceable. Fail-safe-to-strictest is the critical correctness property — a missing tag must never silently downgrade.
Author
Owner

Implemented — PR #56 (open, not merged)

PR: #56

New package ingestion/internal/classification/. Taxonomy public < internal < confidential (ordered → "stricter wins" = max). Config.Derive(Target) / Wing / Repo resolve a destination's level: explicit tag (from optional classification.yaml) wins → client-*=confidential → hyperguild/homelab=internal → everything else=confidential (fail safe).

Design call: central classification.yaml at the brain root, not _index.md frontmatter (BuildWingIndex regenerates it) and not gitea repo topics (would couple #50 to the #52 tracker — chose the server-readable map so #50 has zero dependency on #52, keeping both epic roots parallel-buildable). Auditable in one place (I2/I5).

All ACs met incl. untagged-fails-safe ("" and unknown wings/repos → confidential), stricter-wins, explicit-override, bad-level-in-file → hard error, case-insensitive matching. task check green.

Docs: spec §4.1 "Implemented (#50)" note + brain wiki/hyperguild/decisions/capture-classification-taxonomy.

Unblocks: the I1 gate in #53 and the audit posture in #54 now have a classification source to read. Next on the critical path: #52 (gitea tracker, depends on #51) — and #51 (CaptureService + BrainStore extraction) is the other parallel root, ready to start.

## Implemented — PR #56 (open, not merged) **PR:** https://git.d-ma.be/mathias/hyperguild/pulls/56 New package `ingestion/internal/classification/`. Taxonomy `public < internal < confidential` (ordered → "stricter wins" = `max`). `Config.Derive(Target)` / `Wing` / `Repo` resolve a destination's level: explicit tag (from optional `classification.yaml`) wins → `client-*`=confidential → `hyperguild`/`homelab`=internal → **everything else=confidential (fail safe)**. **Design call:** central `classification.yaml` at the brain root, **not** `_index.md` frontmatter (BuildWingIndex regenerates it) and **not** gitea repo topics (would couple #50 to the #52 tracker — chose the server-readable map so #50 has zero dependency on #52, keeping both epic roots parallel-buildable). Auditable in one place (I2/I5). All ACs met incl. untagged-fails-safe (`""` and unknown wings/repos → confidential), stricter-wins, explicit-override, bad-level-in-file → hard error, case-insensitive matching. `task check` green. Docs: spec §4.1 "Implemented (#50)" note + brain `wiki/hyperguild/decisions/capture-classification-taxonomy`. **Unblocks:** the I1 gate in #53 and the audit posture in #54 now have a classification source to read. Next on the critical path: #52 (gitea tracker, depends on #51) — and #51 (CaptureService + BrainStore extraction) is the other parallel root, ready to start.
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: mathias/hyperguild#50