diff --git a/canon/standards/contrib-templates/br-template.md b/canon/standards/contrib-templates/br-template.md new file mode 100644 index 0000000..3d00a21 --- /dev/null +++ b/canon/standards/contrib-templates/br-template.md @@ -0,0 +1,44 @@ +--- +id: br-YYYY-MM-DD--org--repo--slug +type: br +target_org: +target_repo: +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: + +## Environment + +- **Upstream project**: `/` v`` +- **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._ diff --git a/canon/standards/contrib-templates/ep-template.md b/canon/standards/contrib-templates/ep-template.md new file mode 100644 index 0000000..7469239 --- /dev/null +++ b/canon/standards/contrib-templates/ep-template.md @@ -0,0 +1,50 @@ +--- +id: EP-DOMAIN-NNN +type: ep +ep_id: EP-DOMAIN-NNN +target_org: +target_repo: +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**: `` +**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._ diff --git a/canon/standards/contrib-templates/fr-template.md b/canon/standards/contrib-templates/fr-template.md new file mode 100644 index 0000000..cc91eb0 --- /dev/null +++ b/canon/standards/contrib-templates/fr-template.md @@ -0,0 +1,40 @@ +--- +id: fr-YYYY-MM-DD--org--repo--slug +type: fr +target_org: +target_repo: +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: + +## 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._ diff --git a/canon/standards/contrib-templates/upr-template.md b/canon/standards/contrib-templates/upr-template.md new file mode 100644 index 0000000..b4d9fc1 --- /dev/null +++ b/canon/standards/contrib-templates/upr-template.md @@ -0,0 +1,62 @@ +--- +id: upr-YYYY-MM-DD--org--repo--slug +type: upr +target_org: +target_repo: +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: + +## 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**: `` +**Origin story**: _How/when this component was created locally._ + +## Target Upstream Location + +**Repo**: `/` +**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._ diff --git a/canon/standards/contribution-convention_v0.1.md b/canon/standards/contribution-convention_v0.1.md new file mode 100644 index 0000000..90a8793 --- /dev/null +++ b/canon/standards/contribution-convention_v0.1.md @@ -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 + +``` +/ + contrib/ + bug-reports/ # BR artifacts + feature-requests/ # FR artifacts + extension-points/ # EP artifacts + upstream-prs/ # UPR artifacts +``` + +Each artifact file follows the naming pattern: + +``` +------.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: ------- # unique string ID +type: br | fr | ep | upr # required +target_org: # required +target_repo: # required +title: "Human-readable title" # required +status: draft | submitted | acknowledged | accepted | rejected | merged | withdrawn +domain: custodian | railiance | markitect | ... # originating domain +related_workstream: # optional +state_hub_contribution_id: # 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--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**: `-------` — date-prefixed slug +- **EP**: `EP--NNN` where `` 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. diff --git a/contrib/upstream-prs/2026-02-26--observablehq--framework--toc-sidebar-inject.md b/contrib/upstream-prs/2026-02-26--observablehq--framework--toc-sidebar-inject.md new file mode 100644 index 0000000..01ec910 --- /dev/null +++ b/contrib/upstream-prs/2026-02-26--observablehq--framework--toc-sidebar-inject.md @@ -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`
...
`; +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.