Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .agents/skills/hypercerts-api/references/endpoint-map.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Inspect the exact operation in the bundled OpenAPI contract before constructing
| Browse/filter organizations | `app.certified.actor.listOrganizations` | Use for organization-type/visibility filters and pagination. |
| Find organizations by text | `app.certified.actor.searchOrganizations` | Searches associated profile text, with optional organization filters. |

Use `getProfiles`/`getOrganizations` for known DID sets; use `list` or `search` for discovery. A missing optional profile inside an organization view is not the same as a missing organization record.
Use `getProfiles`/`getOrganizations` for known DID sets; use `list` or `search` for discovery. A missing optional profile inside an organization view is not the same as a missing organization record. Organization actor views from these four endpoints include `location` (the resolved, raw indexed location record, or null; `organization.record.location` stays the strong reference); use it instead of a second `getLocation` call. Organization views nested in other endpoints' author or actor views do not include it.

## Activities, contributors, contributions, and rights (9)

Expand Down
36 changes: 29 additions & 7 deletions .agents/skills/hypercerts-api/references/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"get": {
"operationId": "app_certified_actor_getOrganization",
"tags": ["app.certified.actor"],
"description": "Gets an actor's indexed organization sidecar and associated profile by DID. Authentication is not required.",
"description": "Gets an actor's indexed organization sidecar, associated profile and location by DID. Authentication is not required.",
"parameters": [
{
"name": "actor",
Expand Down Expand Up @@ -117,7 +117,7 @@
},
{
"name": "OrganizationQueryFailed",
"description": "The indexed organization sidecar or associated profile could not be queried."
"description": "The indexed organization sidecar, associated profile or location could not be queried."
}
]
}
Expand All @@ -126,7 +126,7 @@
"get": {
"operationId": "app_certified_actor_getOrganizations",
"tags": ["app.certified.actor"],
"description": "Returns an indexed organization sidecar and associated profile for each supplied actor DID. Authentication is not required.",
"description": "Returns an indexed organization sidecar, associated profile and location for each supplied actor DID. Authentication is not required.",
"parameters": [
{
"name": "actors",
Expand Down Expand Up @@ -165,7 +165,7 @@
},
{
"name": "OrganizationQueryFailed",
"description": "The indexed organization sidecars or associated profiles could not be queried."
"description": "The indexed organization sidecars, associated profiles or locations could not be queried."
}
]
}
Expand Down Expand Up @@ -337,7 +337,7 @@
},
{
"name": "OrganizationQueryFailed",
"description": "The indexed organization sidecar or associated profile could not be queried."
"description": "The indexed organization sidecar, associated profile or location could not be queried."
}
]
}
Expand Down Expand Up @@ -485,7 +485,7 @@
},
{
"name": "OrganizationQueryFailed",
"description": "The indexed organization sidecar or associated profile could not be queried."
"description": "The indexed organization sidecar, associated profile or location could not be queried."
}
]
}
Expand Down Expand Up @@ -4197,9 +4197,23 @@
"record": { "$ref": "#/components/schemas/app.certified.actor.organization.main" }
}
},
"app.certified.actor.getOrganization.locationRecordView": {
"type": "object",
"description": "Indexed app.certified.location record view preserving the full record exactly as getLocation returns it, but without the hydrated author; indexedAt may be null when the index has no timestamp.",
"required": ["uri", "cid", "indexedAt", "did", "record"],
"properties": {
"uri": { "type": "string", "format": "at-uri" },
"cid": { "type": "string", "format": "cid" },
"indexedAt": {
"anyOf": [{ "type": "string", "format": "datetime" }, { "type": "null" }]
},
"did": { "type": "string", "format": "did" },
"record": { "$ref": "#/components/schemas/app.certified.location.main" }
}
},
"app.certified.actor.getOrganization.organizationActorView": {
"type": "object",
"description": "Actor with an indexed organization sidecar and nullable profile view.",
"description": "Actor with an indexed organization sidecar, nullable profile view and nullable location view.",
"required": ["did", "profile", "organization"],
"properties": {
"did": { "type": "string", "format": "did" },
Expand All @@ -4211,6 +4225,14 @@
},
"organization": {
"$ref": "#/components/schemas/org.hypercerts.api.defs.organizationView"
},
"location": {
"anyOf": [
{
"$ref": "#/components/schemas/app.certified.actor.getOrganization.locationRecordView"
},
{ "type": "null" }
]
}
}
},
Expand Down
2 changes: 1 addition & 1 deletion .agents/skills/hypercerts-api/references/recipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ These recipes show endpoint choice and the data to carry between calls. For exac
## Load profile and organization context

1. For one actor profile, call `app.certified.actor.getProfile` with a DID or handle. For many known actor DIDs, use `app.certified.actor.getProfiles` with repeated `actors` values; the returned results correspond to the input occurrences and `profile` can be null.
2. For organization sidecar context, use `app.certified.actor.getOrganization` with an actor DID or batch known DIDs with `app.certified.actor.getOrganizations`. In batch results, an absent organization is represented by a null `organization` for that actor. The organization actor view's `profile` may independently be null.
2. For organization sidecar context, use `app.certified.actor.getOrganization` with an actor DID or batch known DIDs with `app.certified.actor.getOrganizations`. In batch results, an absent organization is represented by a null `organization` for that actor. The organization actor view's `profile` may independently be null. Each organization actor view (`getOrganization`, `getOrganizations`, `listOrganizations`, `searchOrganizations`) also carries `location`: the resolved `app.certified.location` record the sidecar's `location` reference points to, unchanged (a blob payload stays a blob reference, with no URL), or null when the sidecar has no location reference, the reference is not a location record, or that record is not indexed. It is matched by AT-URI, so if its `cid` differs from `organization.record.location.cid` it is a different indexed version, which may be older or newer than the referenced one. No second `getLocation` call is needed.
3. Use `listProfiles` / `listOrganizations` to browse and the corresponding `search...` endpoint for text discovery. Do not try to resolve handles in the batch APIs: their contract is DID input. `getProfile` handle resolution depends on the configured resolver and is not independent DID-document verification.
4. When another endpoint already returns an author/actor view, inspect that view's contract before issuing a second hydration call. Optional profile or organization projections can be null; fetching the full view again may add work without making the indexed data fresher.

Expand Down
36 changes: 28 additions & 8 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,41 @@ name: Deploy

on:
push:
# Each branch deploys to the GitHub environment with the same name.
branches: [staging, production]
branches: [main, staging, production]

permissions:
contents: read

concurrency:
group: deploy-${{ github.ref_name }}
cancel-in-progress: false

jobs:
# Branch and GitHub environment names differ, so map them explicitly here,
# once; the `environment` and `concurrency` keys cannot read workflow `env`.
resolve:
name: Resolve deploy environment
runs-on: ubuntu-latest
outputs:
environment: ${{ steps.map.outputs.environment }}
steps:
- id: map
env:
BRANCH: ${{ github.ref_name }}
run: |
case "$BRANCH" in
main) environment=Test ;;
staging) environment=Staging ;;
production) environment=Production ;;
*) echo "::error::No deploy environment is mapped to branch '$BRANCH'; add it to deploy.yml." >&2; exit 1 ;;
esac
echo "environment=$environment" >> "$GITHUB_OUTPUT"

deploy:
name: Install HappyView modules (${{ github.ref_name }})
name: Install HappyView modules (${{ needs.resolve.outputs.environment }})
needs: resolve
runs-on: ubuntu-latest
environment: ${{ github.ref_name }}
environment: ${{ needs.resolve.outputs.environment }}
# Deploys to one environment run one at a time and are never cancelled midway.
concurrency:
group: deploy-${{ needs.resolve.outputs.environment }}
cancel-in-progress: false
steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand Down
71 changes: 60 additions & 11 deletions docs/openapi.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"tags": [
"app.certified.actor"
],
"description": "Gets an actor's indexed organization sidecar and associated profile by DID. Authentication is not required.",
"description": "Gets an actor's indexed organization sidecar, associated profile and location by DID. Authentication is not required.",
"parameters": [
{
"name": "actor",
Expand Down Expand Up @@ -100,7 +100,7 @@
},
{
"name": "OrganizationQueryFailed",
"description": "The indexed organization sidecar or associated profile could not be queried."
"description": "The indexed organization sidecar, associated profile or location could not be queried."
}
]
}
Expand All @@ -111,7 +111,7 @@
"tags": [
"app.certified.actor"
],
"description": "Returns an indexed organization sidecar and associated profile for each supplied actor DID. Authentication is not required.",
"description": "Returns an indexed organization sidecar, associated profile and location for each supplied actor DID. Authentication is not required.",
"parameters": [
{
"name": "actors",
Expand Down Expand Up @@ -155,7 +155,7 @@
},
{
"name": "OrganizationQueryFailed",
"description": "The indexed organization sidecars or associated profiles could not be queried."
"description": "The indexed organization sidecars, associated profiles or locations could not be queried."
}
]
}
Expand Down Expand Up @@ -366,7 +366,7 @@
},
{
"name": "OrganizationQueryFailed",
"description": "The indexed organization sidecar or associated profile could not be queried."
"description": "The indexed organization sidecar, associated profile or location could not be queried."
}
]
}
Expand Down Expand Up @@ -558,7 +558,7 @@
},
{
"name": "OrganizationQueryFailed",
"description": "The indexed organization sidecar or associated profile could not be queried."
"description": "The indexed organization sidecar, associated profile or location could not be queried."
}
]
}
Expand Down Expand Up @@ -5354,9 +5354,52 @@
}
}
},
"app.certified.location.main": {
"type": "record",
"description": "A location reference"
},
"app.certified.actor.getOrganization.locationRecordView": {
"type": "object",
"description": "Indexed app.certified.location record view preserving the full record exactly as getLocation returns it, but without the hydrated author; indexedAt may be null when the index has no timestamp.",
"required": [
"uri",
"cid",
"indexedAt",
"did",
"record"
],
"properties": {
"uri": {
"type": "string",
"format": "at-uri"
},
"cid": {
"type": "string",
"format": "cid"
},
"indexedAt": {
"anyOf": [
{
"type": "string",
"format": "datetime"
},
{
"type": "null"
}
]
},
"did": {
"type": "string",
"format": "did"
},
"record": {
"$ref": "#/components/schemas/app.certified.location.main"
}
}
},
"app.certified.actor.getOrganization.organizationActorView": {
"type": "object",
"description": "Actor with an indexed organization sidecar and nullable profile view.",
"description": "Actor with an indexed organization sidecar, nullable profile view and nullable location view.",
"required": [
"did",
"profile",
Expand All @@ -5379,6 +5422,16 @@
},
"organization": {
"$ref": "#/components/schemas/org.hypercerts.api.defs.organizationView"
},
"location": {
"anyOf": [
{
"$ref": "#/components/schemas/app.certified.actor.getOrganization.locationRecordView"
},
{
"type": "null"
}
]
}
}
},
Expand Down Expand Up @@ -7060,10 +7113,6 @@
"type": "record",
"description": "A collection/group of items (activities and/or other collections). Collections support recursive nesting."
},
"app.certified.location.main": {
"type": "record",
"description": "A location reference"
},
"org.hypercerts.collection.getCollection.locationRecordView": {
"type": "object",
"description": "Raw location record view with metadata and no author hydration, used for exact-version collection reference projections.",
Expand Down
50 changes: 46 additions & 4 deletions docs/sources/lexicons/app.certified.actor.getOrganization.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"defs": {
"main": {
"type": "query",
"description": "Gets an actor's indexed organization sidecar and associated profile by DID. Authentication is not required.",
"description": "Gets an actor's indexed organization sidecar, associated profile and location by DID. Authentication is not required.",
"parameters": {
"type": "params",
"required": [
Expand Down Expand Up @@ -36,20 +36,57 @@
},
{
"name": "OrganizationQueryFailed",
"description": "The indexed organization sidecar or associated profile could not be queried."
"description": "The indexed organization sidecar, associated profile or location could not be queried."
}
]
},
"locationRecordView": {
"type": "object",
"description": "Indexed app.certified.location record view preserving the full record exactly as getLocation returns it, but without the hydrated author; indexedAt may be null when the index has no timestamp.",
"required": [
"uri",
"cid",
"indexedAt",
"did",
"record"
],
"nullable": [
"indexedAt"
],
"properties": {
"uri": {
"type": "string",
"format": "at-uri"
},
"cid": {
"type": "string",
"format": "cid"
},
"indexedAt": {
"type": "string",
"format": "datetime"
},
"did": {
"type": "string",
"format": "did"
},
"record": {
"type": "ref",
"ref": "app.certified.location"
}
}
},
"organizationActorView": {
"type": "object",
"description": "Actor with an indexed organization sidecar and nullable profile view.",
"description": "Actor with an indexed organization sidecar, nullable profile view and nullable location view.",
"required": [
"did",
"profile",
"organization"
],
"nullable": [
"profile"
"profile",
"location"
],
"properties": {
"did": {
Expand All @@ -63,6 +100,11 @@
"organization": {
"type": "ref",
"ref": "org.hypercerts.api.defs#organizationView"
},
"location": {
"type": "ref",
"ref": "#locationRecordView",
"description": "The organization's location record, as stored (blobs are not resolved). Only returned by getOrganization, getOrganizations, listOrganizations and searchOrganizations. Null if there is no location or it is not indexed. Matched by URI, so it may be a newer version than organization.record.location.cid."
}
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"defs": {
"main": {
"type": "query",
"description": "Returns an indexed organization sidecar and associated profile for each supplied actor DID. Authentication is not required.",
"description": "Returns an indexed organization sidecar, associated profile and location for each supplied actor DID. Authentication is not required.",
"parameters": {
"type": "params",
"required": [
Expand Down Expand Up @@ -37,7 +37,7 @@
},
{
"name": "OrganizationQueryFailed",
"description": "The indexed organization sidecars or associated profiles could not be queried."
"description": "The indexed organization sidecars, associated profiles or locations could not be queried."
}
]
},
Expand Down
Loading
Loading