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:
44
canon/standards/contrib-templates/br-template.md
Normal file
44
canon/standards/contrib-templates/br-template.md
Normal 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._
|
||||
50
canon/standards/contrib-templates/ep-template.md
Normal file
50
canon/standards/contrib-templates/ep-template.md
Normal 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._
|
||||
40
canon/standards/contrib-templates/fr-template.md
Normal file
40
canon/standards/contrib-templates/fr-template.md
Normal 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._
|
||||
62
canon/standards/contrib-templates/upr-template.md
Normal file
62
canon/standards/contrib-templates/upr-template.md
Normal 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._
|
||||
157
canon/standards/contribution-convention_v0.1.md
Normal file
157
canon/standards/contribution-convention_v0.1.md
Normal 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.
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user