feat(canon): add contribution-convention v0.1, contrib/ templates, and first UPR artifact

- canon/standards/contribution-convention_v0.1.md: master spec for BR/FR/EP/UPR
  artifact types, directory layout, frontmatter schema, ID schemes (EP-DOMAIN-NNN
  for extension points), status lifecycle, and relationship to State Hub
- canon/standards/contrib-templates/: four template files (br, fr, ep, upr)
- contrib/upstream-prs/2026-02-26--observablehq--framework--toc-sidebar-inject.md:
  first real UPR artifact — proposes injectTocTop() to Observable Framework

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 17:28:13 +01:00
parent b949a11f20
commit 0d978b1417
6 changed files with 452 additions and 0 deletions

View File

@@ -0,0 +1,44 @@
---
id: br-YYYY-MM-DD--org--repo--slug
type: br
target_org: <github-org-or-owner>
target_repo: <repository-name>
title: "Short description of the bug"
status: draft
domain: custodian # change to your domain
related_workstream: null
state_hub_contribution_id: null
created: "YYYY-MM-DD"
updated: "YYYY-MM-DD"
upstream_version: "X.Y.Z"
upstream_issue_url: null
---
# Bug: <short description>
## Environment
- **Upstream project**: `<target_org>/<target_repo>` v`<upstream_version>`
- **Our usage context**: _which component or module triggered this_
## Reproduction Steps
1.
2.
3.
## Expected Behaviour
_What should happen._
## Actual Behaviour
_What actually happens. Include error messages or stack traces._
## Workaround
_Any workaround currently in use, or "None"._
## Notes
_Any additional context, links to related issues, or observations._

View File

@@ -0,0 +1,50 @@
---
id: EP-DOMAIN-NNN
type: ep
ep_id: EP-DOMAIN-NNN
target_org: <github-org-or-owner>
target_repo: <repository-name>
title: "Short description of the extension point"
status: draft
domain: custodian # change to your domain
related_workstream: null
state_hub_contribution_id: null
created: "YYYY-MM-DD"
updated: "YYYY-MM-DD"
location: "src/file.ts:42"
upstream_issue_url: null
---
# Extension Point Proposal: EP-DOMAIN-NNN
## Summary
_One-paragraph description of the extension point: where in the upstream codebase
it would live, what it would enable, and who would benefit._
## Location
**File**: `<path/in/upstream/repo>`
**Line**: _approximate location where the hook/callback would be inserted_
## Proposed Interface
```typescript
// or Python, Rust, etc. — match the upstream project's language
interface ExtensionPoint {
// …
}
```
## Rationale
_Why this extension point is valuable. What use cases does it unlock?
Why should upstream accept it rather than keeping it local?_
## Implementation Sketch
_Brief notes on how upstream might implement this, if relevant._
## Notes
_References to related upstream issues, PRs, or discussions._

View File

@@ -0,0 +1,40 @@
---
id: fr-YYYY-MM-DD--org--repo--slug
type: fr
target_org: <github-org-or-owner>
target_repo: <repository-name>
title: "Short description of the requested feature"
status: draft
domain: custodian # change to your domain
related_workstream: null
state_hub_contribution_id: null
created: "YYYY-MM-DD"
updated: "YYYY-MM-DD"
upstream_issue_url: null
---
# Feature Request: <short description>
## Motivation
_Why we need this feature. What problem does it solve? What becomes possible?_
## Proposed Interface / API
```
# Sketch of the proposed interface, function signature, or configuration option.
```
## Example Usage
```
# How we would use this feature in our codebase once available.
```
## Alternatives
_What we currently do instead (workaround, local implementation, etc.)._
## Notes
_Any additional context, links to related discussions, or upstream roadmap references._

View File

@@ -0,0 +1,62 @@
---
id: upr-YYYY-MM-DD--org--repo--slug
type: upr
target_org: <github-org-or-owner>
target_repo: <repository-name>
title: "Short description of the upstream PR"
status: draft
domain: custodian # change to your domain
related_workstream: null
state_hub_contribution_id: null
created: "YYYY-MM-DD"
updated: "YYYY-MM-DD"
local_component_path: "relative/path/in/this/repo/component.js"
target_upstream_file: "path/in/upstream/repo/component.js"
upstream_pr_url: null
---
# Upstream PR: <short description>
## Summary
_What this PR adds or fixes in the upstream project._
## Motivation
_Why we want this upstream rather than keeping it as a local fork.
What maintenance burden does upstreaming remove?_
## Local Component
**Path in this repo**: `<local_component_path>`
**Origin story**: _How/when this component was created locally._
## Target Upstream Location
**Repo**: `<target_org>/<target_repo>`
**File**: `<target_upstream_file>`
## Draft PR Body
```markdown
## Summary
_Fill in the PR summary for the upstream project here._
## Motivation
_Explain why the upstream project would benefit._
## Changes
-
## Testing
- [ ] Tests added
- [ ] Existing tests pass
```
## Notes
_Any upstream discussion, review feedback, or open questions._

View File

@@ -0,0 +1,157 @@
---
id: canon-contrib-convention
type: standard
title: "Contribution Convention v0.1"
domain: custodian
status: active
version: "0.1"
created: "2026-02-28"
---
# Contribution Convention v0.1
## Purpose
This document defines the canonical convention for tracking upstream contributions
across all custodian-ecosystem repositories. A *contribution* is any intentional
engagement with an external upstream project: a bug report, feature request,
extension-point proposal, or pull request.
Contributions are tracked as Markdown artifacts with typed YAML frontmatter,
committed to the repository that authors them, and indexed in the State Hub DB.
This enables the Custodian to maintain a full audit trail of all upstream
engagement across all six project domains.
## Artifact Types
| Code | Name | Description |
|------|------|-------------|
| `br` | Bug Report | A defect reported to an upstream project |
| `fr` | Feature Request | A capability requested from an upstream project |
| `ep` | Extension-Point Proposal | A proposed extension point in an upstream project |
| `upr`| Upstream PR | A pull request submitted or planned for upstream |
## Directory Layout
```
<repo-root>/
contrib/
bug-reports/ # BR artifacts
feature-requests/ # FR artifacts
extension-points/ # EP artifacts
upstream-prs/ # UPR artifacts
```
Each artifact file follows the naming pattern:
```
<YYYY-MM-DD>--<org>--<repo>--<slug>.md
```
Examples:
- `contrib/bug-reports/2026-03-01--observablehq--framework--plot-tooltip-flicker.md`
- `contrib/upstream-prs/2026-02-26--observablehq--framework--toc-sidebar-inject.md`
- `contrib/extension-points/EP-CUST-002--anthropic--claude-code--hook-on-tool-result.md`
## Frontmatter Schema
All contribution artifacts share a common base frontmatter:
```yaml
---
id: <type>-<YYYY-MM-DD>--<org>--<repo>--<slug> # unique string ID
type: br | fr | ep | upr # required
target_org: <github-org-or-owner> # required
target_repo: <repository-name> # required
title: "Human-readable title" # required
status: draft | submitted | acknowledged | accepted | rejected | merged | withdrawn
domain: custodian | railiance | markitect | ... # originating domain
related_workstream: <workstream-slug> # optional
state_hub_contribution_id: <uuid> # set once registered in State Hub
created: "YYYY-MM-DD"
updated: "YYYY-MM-DD"
---
```
### BR — Bug Report (additional fields)
```yaml
upstream_version: "1.2.3" # version where bug was observed
reproduction_steps: |
1. …
2. …
expected: "What should happen"
actual: "What actually happens"
workaround: "Any known workaround" # optional
upstream_issue_url: "https://…" # optional — link once filed
```
### FR — Feature Request (additional fields)
```yaml
motivation: "Why this feature is needed"
proposed_api: |
# Sketch of the proposed interface
alternatives: "What we do instead today"
upstream_issue_url: "https://…" # optional
```
### EP — Extension-Point Proposal (additional fields)
```yaml
ep_id: EP-<DOMAIN>-NNN # e.g. EP-RAIL-007
location: "src/file.ts:42" # file:line in upstream where hook would live
proposed_interface: |
# Interface or callback signature sketch
rationale: "Why this extension point is valuable"
upstream_issue_url: "https://…" # optional
```
### UPR — Upstream PR (additional fields)
```yaml
local_component_path: "relative/path/in/this/repo"
target_upstream_file: "path/in/upstream/repo"
upstream_pr_url: "https://…" # set once submitted
draft_pr_body: |
## Summary
## Motivation
```
## ID Schemes
- **BR / FR / UPR**: `<type>-<YYYY-MM-DD>--<org>--<repo>--<slug>` — date-prefixed slug
- **EP**: `EP-<DOMAIN>-NNN` where `<DOMAIN>` is uppercase (CUST, RAIL, MARK, etc.)
and `NNN` is a zero-padded three-digit sequence per domain (EP-CUST-001,
EP-CUST-002, …). This scheme is an extension of the Railiance EP convention
defined in the staged-promotion-lifecycle workstream; this canon document is
the authoritative master spec.
## Status Lifecycle
```
draft → submitted → acknowledged → accepted → merged
↘ ↘
rejected withdrawn
```
- `draft`: artifact created locally, not yet sent upstream
- `submitted`: issue filed or PR opened upstream
- `acknowledged`: upstream team has responded
- `accepted`: upstream has agreed to the proposal
- `rejected`: upstream has declined
- `merged`: PR merged / fix released
- `withdrawn`: we decided not to pursue
## Relationship to State Hub
Once an artifact is registered via `register_contribution()` MCP tool or
`POST /contributions/` API, the State Hub assigns a UUID and returns it.
That UUID is written back into `state_hub_contribution_id` in the frontmatter.
The State Hub is a **read/cache layer** — the Markdown file is always the
authoritative source of truth. If the DB is reset, contributions can be
re-ingested from the files.

View File

@@ -0,0 +1,99 @@
---
id: upr-2026-02-26--observablehq--framework--toc-sidebar-inject
type: upr
target_org: observablehq
target_repo: framework
title: "Add injectTocTop() utility for injecting elements into the TOC sidebar"
status: draft
domain: custodian
related_workstream: contribution-tracking-sbom
state_hub_contribution_id: null
created: "2026-02-26"
updated: "2026-02-28"
local_component_path: "state-hub/dashboard/src/components/toc-sidebar.js"
target_upstream_file: "src/client/toc.ts"
upstream_pr_url: null
---
# Upstream PR: Add injectTocTop() utility for injecting elements into the TOC sidebar
## Summary
Propose adding an `injectTocTop(id, element)` utility to Observable Framework
that allows dashboard pages to prepend arbitrary HTML elements at the top of the
automatically-generated table-of-contents sidebar. This enables KPI cards, live
status indicators, and other contextual widgets to live alongside the page's
section links.
## Motivation
Observable Framework generates a TOC sidebar from headings automatically, but
provides no standard way to inject content into it from page JavaScript. As a
result, every project that wants sidebar widgets must implement its own DOM
manipulation workaround.
By upstreaming a small, focused utility, the community gets a stable API for
sidebar injection that doesn't depend on Observable Framework's internal DOM
structure.
## Local Component
**Path in this repo**: `state-hub/dashboard/src/components/toc-sidebar.js`
**Origin story**: Created 2026-02-26 during implementation of the Decisions KPI
dashboard (State Hub v0.2). The component provides two utilities:
- `injectTocTop(id, element)`: remove-then-prepend to the TOC aside element
- `withDocHelp(element, docPath)`: attaches a `?` button that opens a doc page
as an iframe overlay
## Target Upstream Location
**Repo**: `observablehq/framework`
**File**: `src/client/toc.ts` (or a new `src/client/toc-inject.ts`)
## Draft PR Body
```markdown
## Summary
Add `injectTocTop(id, element)` — a small utility for injecting custom elements
at the top of the Observable Framework table-of-contents sidebar.
## Motivation
Dashboard pages frequently need contextual widgets (KPI boxes, live status
indicators, navigation aids) that belong alongside the TOC, not in the page
content flow. Currently this requires each project to directly manipulate the
`#observablehq-toc` DOM element, coupling page code to an internal DOM detail.
`injectTocTop` provides a stable API for this pattern:
```js
import {injectTocTop} from "observablehq:toc";
const myWidget = html`<div class="kpi-box">...</div>`;
injectTocTop("my-kpi-box", myWidget);
```
## Changes
- Add `injectTocTop(id: string, element: HTMLElement): void` to Framework's
client runtime
- Export from the `observablehq:toc` module (or equivalent public API)
- Add documentation page: "Customising the sidebar"
## Testing
- [ ] Unit test: `injectTocTop` prepends element to `#observablehq-toc aside`
- [ ] Unit test: calling again with same `id` removes old element before
inserting new one (idempotent)
- [ ] Integration test: injected element appears above TOC links in rendered page
```
## Notes
- The local implementation (`toc-sidebar.js`) uses `querySelector('#observablehq-toc aside')`
— this should be replaced with a stable API reference once upstreamed.
- The `withDocHelp` utility in the same file is a separate feature; this PR
focuses solely on `injectTocTop`.
- Observable Framework issue tracker should be checked for any existing
discussion of sidebar customisation before opening a new issue.