mirror of
https://github.com/profullstack/logicsrc.git
synced 2026-08-13 14:37:26 +00:00
Add the LogicSRC OpenContext specification (#132)
* Add the LogicSRC OpenContext specification OpenContext is an open specification for durable, portable, permissioned, provenance-aware context shared between humans and AI agents. It defines how organizational knowledge is described, authorized, versioned, resolved, audited, and handed between replaceable workers without losing institutional state. Follows the OpenPRD/OpenOntology pattern already in the repo: self-contained JSON Schemas in @logicsrc/schemas, a reference implementation package, CLI subcommands, docs, examples, and an OpenPRD record. Schemas (8, all self-contained so a third party can fetch one file and validate against it with no further resolution): manifest, object, bundle, role, provenance, decision, diagnostic, audit-event — registered in @logicsrc/validators and schemas:validate. Reference implementation (@logicsrc/opencontext): loader with upward manifest discovery, the full resolution pipeline, authority/supersession, permissions, redaction, lifecycle, provenance, deterministic digests, doctor, search, graph, history/diff, guarded writes, audit events, and file/http/git/sqlite adapters. CLI: all 15 specified commands, as a standalone `opencontext` binary and as `logicsrc context`, sharing one implementation so the two cannot drift. Design decisions worth noting: - Supersession is declared, never inferred from version numbers. Inferring it would hide the governance failure it represents and make multiple-active-versions and duplicate-canonical impossible to detect. - The bundle digest identifies the resolved context, not the moment it was computed, so generated_at/bundle_id/digest/as_of are excluded while objects, lifecycle states, exclusions and warnings are covered. That is what lets a decision record cite exactly the context that produced it. - A role's own max_classification beats an inherited one, so a ceiling on a shared base role cannot silently cap a role deliberately granted more; requesting several roles at once still takes the lowest, so combining roles never escalates. - Scope wildcards match whole dotted segments only. A trailing .* covers a subtree; an interior * matches exactly one segment. Substring matching here would be an access-control bug. - --include narrows an existing scope and is applied after it, never merged into it, so a request can never widen what a role holds. Verified: 226 tests across core primitives, permissions/redaction, the resolution pipeline, security, the published conformance fixtures (13 valid, 35 invalid, 8 resolution scenarios), project behaviour, and the five shipped examples — which are held to --strict and a 100% health score. Benchmarks meet every published budget (resolve 1,000 objects in ~33ms against a 2s target). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Point install docs at @logicsrc/opencontext; record the npm name collision The unscoped `opencontext` name is already published on npm by an unrelated third party (federicodeponte/opencontext, 2.0.0), so `npx opencontext` would install a stranger's package. Docs now use `npx @logicsrc/opencontext`; the bin stays named `opencontext` so the command reads as the PRD specifies once installed. Recorded in PRD 0003 as a blocker to resolve before any publication, along with the fact that no @logicsrc spec package has ever been published, so there is no existing release path to slot into. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> * Advance the logicsrc-mcp next-PRD-id assertion to 0004 standards.test.ts asserts prd_next_id against the live prd/ directory, so adding PRD 0003 makes the next free id 0004. The test's own comment anticipates this: "advances with every PRD added". Caught by CI, not locally — the earlier verification ran per-package tests for the packages this branch touches, and logicsrc-mcp is coupled to the PRD directory without importing from it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1bb7ba6e60
commit
3ab8a4b38b
212 changed files with 17249 additions and 7 deletions
256
docs/opencontext/context-object.md
Normal file
256
docs/opencontext/context-object.md
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
# Context object reference
|
||||
|
||||
One durable unit of context: a mission statement, a policy, an SOP, a customer fact, a decision, a piece of operational state.
|
||||
|
||||
Schema: `https://logicsrc.com/schemas/opencontext/object.schema.json`
|
||||
|
||||
Only `id` and `type` are required. Everything else exists so context can be *governed* rather than merely stored.
|
||||
|
||||
## Three ways to write one
|
||||
|
||||
**Markdown with front matter** — metadata in the fence, prose as content. The usual choice.
|
||||
|
||||
```yaml
|
||||
---
|
||||
id: policies.refunds
|
||||
type: policy
|
||||
layer: L3
|
||||
title: Refund policy
|
||||
authority: canonical
|
||||
owner: support
|
||||
updated: 2026-08-09T00:00:00Z
|
||||
---
|
||||
|
||||
Refund requests are accepted within 30 days of purchase.
|
||||
```
|
||||
|
||||
**YAML or JSON** — the whole document is the object. Use this when content is structured.
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "customers.acme",
|
||||
"type": "customer",
|
||||
"content": { "name": "ACME Inc.", "plan": "enterprise" }
|
||||
}
|
||||
```
|
||||
|
||||
**Markdown with no front matter** — still a valid object. The body is the content, and the collection supplies `id` and `type`. This is what makes OpenContext adoptable: point it at an existing `docs/` folder and it works, then add metadata where governance actually matters.
|
||||
|
||||
## Identity
|
||||
|
||||
| Field | Notes |
|
||||
| --- | --- |
|
||||
| `id` | **Required.** Stable, unique in the namespace. Dotted lowercase. Renaming is a breaking change — prefer supersession. |
|
||||
| `type` | **Required.** Open vocabulary: `mission`, `policy`, `procedure`, `decision`, `product`, `customer`, `knowledge`, `note`… A validator must not reject an unknown type. |
|
||||
| `layer` | `L0`–`L5`. Describes the *kind* of knowledge, never its authority. |
|
||||
| `title` | Short heading. Used by search, ranking, and Markdown rendering. |
|
||||
| `summary` | One or two sentences. A resolver may compile this instead of full content when minimising context. |
|
||||
|
||||
## Content
|
||||
|
||||
| Field | Notes |
|
||||
| --- | --- |
|
||||
| `content` | Inline. A string for prose; an object or array for structured data. |
|
||||
| `content_type` | e.g. `text/markdown`, `application/json`. |
|
||||
| `content_uri` | Where content loads from when not inline: `file://`, `http://`, `https://`, `git://`, `sqlite://`, or any scheme an installed adapter claims. |
|
||||
|
||||
An unknown scheme fails clearly. It is never resolved to empty content — a bundle that silently omits the pricing it was asked about is worse than an error, because nothing looks wrong.
|
||||
|
||||
OpenContext does not assume all context is prose.
|
||||
|
||||
## Authority and trust
|
||||
|
||||
```yaml
|
||||
authority: canonical
|
||||
trust: trusted
|
||||
```
|
||||
|
||||
**`authority`** — how much this counts as truth. Declared by the owner of the context, never inferred from retrieval rank, recency, or what the content says about itself.
|
||||
|
||||
| Level | Meaning |
|
||||
| --- | --- |
|
||||
| `canonical` | The organization's own source of truth |
|
||||
| `approved` | Reviewed and sanctioned |
|
||||
| `reference` | Useful, not binding |
|
||||
| `observed` | Seen in the wild, unverified |
|
||||
| `inferred` | Derived by a model or heuristic |
|
||||
| `historical` | Retained for the record only |
|
||||
|
||||
Default when omitted: `reference`.
|
||||
|
||||
**`trust`** — where the content came from, in terms of whether it can be believed.
|
||||
|
||||
| Level | Meaning |
|
||||
| --- | --- |
|
||||
| `trusted` | Authored inside the trust boundary |
|
||||
| `verified` | External but integrity-checked |
|
||||
| `untrusted` | Arrived from a system that can carry attacker-controlled text |
|
||||
|
||||
These are different axes. An object can be `authority: canonical` about a fact while the fact's *content* is `trust: untrusted` — and that combination is a validation error, because canonical means the organization vouches for it, and you cannot vouch for text a stranger typed into a form.
|
||||
|
||||
## Ownership and approval
|
||||
|
||||
| Field | Notes |
|
||||
| --- | --- |
|
||||
| `owner` | Accountable role, team, or identity. `doctor` reports unowned objects, because unowned context is what goes stale. |
|
||||
| `status` | `draft`, `pending`, `approved`, `rejected`, `retired`. Drafts and pending objects are excluded from default resolution. |
|
||||
| `approval` | Requirements and recorded approvals. An object requiring two approvals and carrying one is not approved. |
|
||||
| `review` | Cadence. Overdue reviews are reported. |
|
||||
|
||||
```yaml
|
||||
approval:
|
||||
required: true
|
||||
roles: [legal, executive]
|
||||
minimum: 1
|
||||
approved_by:
|
||||
- role: legal
|
||||
id: counsel@example.com
|
||||
at: 2026-08-08T10:00:00Z
|
||||
```
|
||||
|
||||
## Time
|
||||
|
||||
| Field | Notes |
|
||||
| --- | --- |
|
||||
| `created` | RFC 3339. |
|
||||
| `updated` | RFC 3339. Freshness is measured from here. |
|
||||
| `valid_from` | Object is `future` and excluded before this instant. |
|
||||
| `expires` | Object is `expired` after this instant. Explicit `null` means never expires — different from omitting the field. |
|
||||
| `ttl` | Per-object staleness window, overriding `freshness.default_ttl`. |
|
||||
| `durability` | `ephemeral`, `session`, `operational`, `long-lived`, `permanent`. |
|
||||
|
||||
Lifecycle state is always computed against a timestamp and never stored. See [lifecycle](./lifecycle.md).
|
||||
|
||||
## Access
|
||||
|
||||
```yaml
|
||||
classification: internal
|
||||
permissions:
|
||||
read: [sales-agent, finance-agent]
|
||||
write: [sales-admin]
|
||||
deny: [contractor]
|
||||
redact:
|
||||
- path: ssn
|
||||
mode: remove
|
||||
```
|
||||
|
||||
`classification` is one of `public`, `internal`, `confidential`, `restricted`, and bounds who may read the object regardless of scope.
|
||||
|
||||
`permissions.read` narrows a role that would otherwise include the object. `deny` overrides everything. An absent `read` list means the repository scope rules decide.
|
||||
|
||||
Read access never implies write access.
|
||||
|
||||
## Relationships
|
||||
|
||||
| Field | Notes |
|
||||
| --- | --- |
|
||||
| `supersedes` | Objects this replaces, as `id` or `id@version`. |
|
||||
| `superseded_by` | Set on the older object when the chain is written explicitly. |
|
||||
| `conflicts_with` | Objects known to contradict this one. |
|
||||
| `references` | Context this cites. Drives the graph and orphan detection. |
|
||||
| `depends_on` | Context that must resolve alongside this for it to make sense. |
|
||||
| `applies_to` | Roles, agents, products, or scopes this is about. The strongest relevance signal, because it is the author saying explicitly what the context is for. |
|
||||
|
||||
Every reference must point at something that exists. A broken chain silently resurrects retired policy, so it is an error rather than a no-op.
|
||||
|
||||
## Provenance
|
||||
|
||||
```yaml
|
||||
canonical_source: true
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```yaml
|
||||
sources:
|
||||
- uri: git://github.com/acme/context/policies/refunds.md
|
||||
type: document
|
||||
retrieved_at: 2026-08-09T15:00:00Z
|
||||
digest: sha256:9f2c…
|
||||
trust: trusted
|
||||
```
|
||||
|
||||
`canonical_source: true` says this object *is* the origin — a mission statement written here has no upstream. Anything mirrored from another system should name it. See [provenance](./provenance.md).
|
||||
|
||||
## Confidence and tags
|
||||
|
||||
```yaml
|
||||
confidence: 0.6
|
||||
tags: [pricing, enterprise]
|
||||
```
|
||||
|
||||
`confidence` breaks ties *within* an authority level. It never promotes an object across levels — a model that is 99% sure does not thereby outrank a reviewed policy.
|
||||
|
||||
## Extensions
|
||||
|
||||
```yaml
|
||||
extensions:
|
||||
com.example.risk:
|
||||
score: 0.25
|
||||
```
|
||||
|
||||
Reverse-DNS namespaced. Preserved through resolution and into the bundle.
|
||||
|
||||
## Full example
|
||||
|
||||
```yaml
|
||||
id: pricing.enterprise
|
||||
type: policy
|
||||
layer: L3
|
||||
title: Enterprise Pricing
|
||||
content: |
|
||||
Enterprise plans start at $2,500/month.
|
||||
authority: canonical
|
||||
owner: sales
|
||||
version: 3
|
||||
created: 2026-07-01T00:00:00Z
|
||||
updated: 2026-08-09T00:00:00Z
|
||||
valid_from: 2026-08-01T00:00:00Z
|
||||
expires: null
|
||||
durability: long-lived
|
||||
classification: internal
|
||||
permissions:
|
||||
read: [sales-agent, finance-agent]
|
||||
write: [sales-admin]
|
||||
sources:
|
||||
- uri: crm://pricing/enterprise
|
||||
type: canonical-record
|
||||
supersedes:
|
||||
- pricing.enterprise@2
|
||||
confidence: 1.0
|
||||
tags: [pricing, enterprise]
|
||||
```
|
||||
|
||||
## Decision records
|
||||
|
||||
A decision is an ordinary context object with `type: decision` and a few extra fields. Schema: `https://logicsrc.com/schemas/opencontext/decision.schema.json`.
|
||||
|
||||
```yaml
|
||||
id: decisions.2026-08-09-model-provider
|
||||
type: decision
|
||||
layer: L5
|
||||
title: Default model provider
|
||||
authority: approved
|
||||
owner: platform
|
||||
status: accepted
|
||||
decision: Use provider X as the default runtime.
|
||||
rationale:
|
||||
- latency
|
||||
- cost
|
||||
- reliability
|
||||
alternatives:
|
||||
- option: provider Y
|
||||
rejected_because: no EU region
|
||||
consequences:
|
||||
- Re-evaluate at renewal.
|
||||
approved_by:
|
||||
- role: CTO
|
||||
bundle:
|
||||
bundle_id: ocb_37c04d801d013b07
|
||||
digest: sha256:37c04d80…
|
||||
created: 2026-08-09T15:00:00Z
|
||||
```
|
||||
|
||||
`status` for a decision is `proposed`, `accepted`, `rejected`, `superseded`, or `deprecated`.
|
||||
|
||||
The `bundle` block is what makes a decision auditable rather than merely recorded: citing the digest lets a reader prove which context was — and was not — in front of the decider. Reversing a decision supersedes it; it does not delete it.
|
||||
Loading…
Add table
Add a link
Reference in a new issue