Compare commits

...

2 commits

Author SHA1 Message Date
a e6c076a8f4 add page about tagging 2024-06-03 15:45:49 -05:00
a 4f9ba31228 update 2024-06-03 15:45:18 -05:00
10 changed files with 142 additions and 73 deletions

View file

@ -1,4 +1,4 @@
There are special collections that are managed by server side-effects, such as `followers` `following` `liked` on actors and possibly `replies`, `likes`, `shares` on objects. In most cases, the side-effects are the only intended way of interacting with these collections; for example, a Follow results in an Accept Follow, which has the side effect of adding them to `followers` and them adding you to `following`; a Like has the side effect of you adding the object to `liked` and them adding your Like to `likes`; an Announce has the side effect of them adding the Announce to `shares`, and a small exception for `replies` which may be managed manually.
There are special collections that are managed by server side-effects, such as `followers` `following` `liked` on actors and possibly ~~`replies`~~, `likes`, `shares` on objects. In most cases, the side-effects are the only intended way of interacting with these collections; for example, a Follow results in an Accept Follow, which has the side effect of adding them to `followers` and them adding you to `following`; a Like has the side effect of you adding the object to `liked` and them adding your Like to `likes`; an Announce has the side effect of them adding the Announce to `shares`, and a small exception for `replies` which may be managed manually.
But there's nothing in ActivityPub explicitly preventing a user from targeting their followers/following with an Add/Remove. In the case of a Remove, you can say that there is a legitimate use-case for this; perhaps you no longer wish to follow or be followed by a certain actor. However, for Add, it's a bit weirder -- you can Add an actor to your `followers` despite never receiving a Follow from them. You can add an actor to your `following` despite never receiving an Accept Follow from them.
@ -12,4 +12,6 @@ and in 6.6/6.7 for Add/Remove:
Taken together, we conclude that the logical `iff` regarding Accept Follow is the only way to add the other actor to your following. A C2S Add/Remove would not be allowed due to "discretion".
Given this: how do we signal server management instead of actor management of these collections? My initial leaning would be to exclude `attributedTo` from the representation of these collections; in the absence of any attribution, it is assumed that the collection is owned by the server running at that origin / domain / hostname. (For S2S follower removal, this would have to be a special case handled similarly to Reject Follow being sent at any time after an Accept Follow, but that's a separate topic.)
Given this: how do we signal server management instead of actor management of these collections? My initial leaning would be to exclude `attributedTo` from the representation of these collections; in the absence of any attribution, it is assumed that the collection is owned by the server running at that origin / domain / hostname. (For S2S follower removal, this would have to be a special case handled similarly to Reject Follow being sent at any time after an Accept Follow, but that's a separate topic.)
https://github.com/w3c/activitypub/issues/377

View file

@ -0,0 +1 @@
Collection mechanism is very similar to ldp:Container and i guess solid as well? can be backed by filesystem directory/folder and files.

View file

@ -0,0 +1,3 @@
if you turn everything into an actor, then Following that actor is like subscribing to a topic for that actor
the actor's role is to programmatically forward or announce activities/objects related to that topic?

View file

@ -4,4 +4,4 @@ consider an unlisted youtube video, which doesn't appear in the uploads tab. how
instead: have an explicit profile Collection. Add stuff into it. when we federate social data we should explicitly be managing the expected presentation of that social data, in as generic a way as possible.
related problem: constructing conversations based on a chain of `inReplyTo` instead of having an explicit collection (likely being used as `context`)
related problem: constructing conversations based on a chain of `inReplyTo` instead of having an explicit collection (likely being used as `context`) -- actually the activitypub spec [doesn't specify side effects for inReplyTo]({{< relref "replies-have-no-side-effect" >}}) and for that matter neither does it specify use of context or a context-collection. these are both cases where the Add makes sense to send out explicitly.

View file

@ -1,4 +1,4 @@
see [Note vs Article]({{<relref "note-vs-article.md" >}}) for more. but basically:
see [Note vs Article]({{<relref "note-vs-article" >}}) for more. but basically:
in summary:

View file

@ -27,4 +27,8 @@ what might this imply is needed for activitypub?
## querying
how do you tell if an arbitrary object is included in a collection or not? without iterating over the entire collection, that is.
how do you tell if an arbitrary object is included in a collection or not? without iterating over the entire collection, that is.
## constraining range
how do you know what a collection contains?

View file

@ -5,4 +5,4 @@ the recommendation in the spec is to use JSON-LD for extensions, which leaves op
my thoughts:
- if you consider the mastodon protocol/profile, then you basically have to compact against the same context as them, because mastodon only understands shorthand terms that match their own definitions.
- a full IRI is the only unambiguous way to refer to the same thing
- a full IRI is the only unambiguous way to refer to the same thing. namespaces / prefixes are bad because you could have infinitely many ways of expressing the same thing

View file

@ -0,0 +1,4 @@
`likes` and `shares` are defined in terms of side effects of `Like` and `Announce`, but there is no specified side effect for `Create` with `inReplyTo`. this implies manual management of the replies collection?
https://github.com/w3c/activitypub/issues/374

View file

@ -0,0 +1,38 @@
it's often stated that hierarchical categories are too limited and that a tagging system is better. putting aside arguments about what a "category" represents taxonomically and how it differs from a "tag" (e.g. "grouping vs describing", "general vs specific", etc), there ought to be more flexibility in tags and tagging in order to make it a worthwhile mental model shift vs. categories.
i generally agree that a strict hierarchy is not the best, even if it is sometimes (often?) good (enough?). the classic issue is with e.g. folders in a filesystem, a folder can have only one parent. sure you can set up symlinks but the one-parent rule is an issue that needs to be worked around.
the shift from categories to tags "solves" this "one-parent rule" issue. (but again, you could just as easily say that an item can belong to multiple categories; etc etc. we leave this argument out because it is too similar to the taxonomic argument above)
now we have to come up with improvements to the tagging system. below are some mechanisms
## hierarchical tags
> x.y.z implies x.y and also implies x. it might also imply y (unclear)
cons: it replicates the one-parent rule and its issues, and it's unclear how inheritance works. also what do you use as the separator between hierarchy layers? a dot? a slash?
prior art:
- also called "nested tags" by obsidian
## taggable tags
just like modern OOP principles tell you to favor composition over inheritance, we favor taggable tags over hierarchical tags.
> z is tagged with x and y; therefore, anything tagged with z implies x and implies y
example: tagging a character from a series implies tagging the series. #gaimon_(one_piece) is your classic booru style binary tag that is too basic. what you *want* is to imply that #one_piece tag without actually having to tag it yourself. but you also want to imply many other tags: #green_hair, #treasure_chest, #afro, and so on. you don't want to add these tags yourself every single time.
prior art:
- hydrus network calls this "tag parents". it works off of semantic subsets and supersets.
## tag aliases
> z implies zee (and vice versa); z implies zed (and vice versa)
prior art:
- also called "tag siblings" by hydrus network. allows you to set up equivalence between semantic concepts.
you can chain these together transitively or keep them flat, but it is generally a good idea to mark one of the ends as "canonical" implying it overrides the other. say you want to have a common misspelling be overridden by the correct spelling

View file

@ -1,85 +1,92 @@
{{ "<!-- title -->" | safeHTML }}
{{- $firstH1 := partial "name.html" . }}
{{- $title := or .Title $firstH1 $.File.ContentBaseName }}
{{- if $title }}
<title itemprop="name">{{ $title }} - {{ .Site.Title }}</title>
{{- else }}
<title itemprop="name">{{ .Site.Title }}</title>
{{- end }}
<meta property="og:title" content="{{ $title }}" />
<meta name="twitter:title" content="{{ $title }}" />
<meta name="application-name" content="{{ .Site.Title }}" />
<meta property="og:site_name" content="{{ .Site.Title }}" />
{{- $cover := ($.Resources.ByType "image").GetMatch "{*opengraph*}" -}}
{{ $icon := resources.GetMatch (default "" .Site.Params.icon) -}}
{{/*=== title ===*/}}
{{ "<!-- text -->" | safeHTML }}
{{- with .Site.Title }}
<meta name="application-name" property="og:site_name" content="{{ . }}" />
{{- end -}}
{{- if .IsHome}}
{{- with or .Params.name .Site.Title }}
<title>{{ . }}</title>
<meta property="og:title" name="twitter:title" itemprop="name" content="{{ . }}" />
{{- end }}
{{- else }}
<title>{{ or .Params.name (print $title " - " .Site.Title) }}</title>
<meta property="og:title" name="twitter:title" itemprop="name" content="{{ or .Params.name $title }}" />
{{- end -}}
{{/*=== description ===*/}}
{{- with or .Description .Summary .Site.Params.description }}
{{ "<!-- description -->" | safeHTML }}
<meta name="description" content="{{.}}">
<meta itemprop="description" content="{{.}}" />
<meta property="og:description" content="{{.}}" />
<meta name="twitter:description" content="{{.}}" />
<meta name="description" itemprop="description" property="og:description" content="{{ . }}" />
<meta name="twitter:description" content="{{ . }}" />
{{- end }}
{{ "<!-- url -->" | safeHTML }}
<base href="{{ .Permalink | absURL }}">
<link rel="canonical" href="{{ .Permalink | absURL }}" itemprop="url" />
<meta name="url" content="{{ .Permalink | absURL }}" />
<meta name="twitter:url" content="{{ .Permalink | absURL }}" />
<meta property="og:url" content="{{ .Permalink | absURL }}" />
{{- with .Permalink | absURL}}
<base href="{{ . }}" />
<link rel="canonical" href="{{ or $.Params.canonical . }}" />
<meta name="url" property="og:url" itemprop="url" content="{{ . }}" />
<meta name="twitter:url" content="{{ . }}" />
{{- end -}}
{{- $cover := ($.Resources.ByType "image").GetMatch "{*cover*,*thumbnail*,*featured*}" -}}
{{ $icon := resources.GetMatch (default "" .Site.Params.icon) -}}
{{/*=== image ===*/}}
{{- $staticIcon := "icon.png" | absURL -}}
{{- with or $cover $icon }}
{{- with or $cover $icon }}
{{ "<!-- image -->" | safeHTML }}
<meta itemprop="image" content='{{ .Permalink | absURL }}' />
<meta property="og:image" content='{{ .Permalink | absURL }}' />
<meta property="og:image" itemprop="image" content="{{ .Permalink | absURL }}" />
{{- with .Width }}
<meta property="og:image:width" content='{{ . }}' />
<meta property="og:image:width" content="{{ . }}" />
{{- end }}
{{- with .Height }}
<meta property="og:image:height" content='{{ . }}' />
<meta property="og:image:height" content="{{ . }}" />
{{- end }}
<meta name="twitter:image" content='{{ .Permalink | absURL }}' />
<meta name="twitter:image:src" content='{{ .Permalink | absURL }}' />
<meta name="twitter:image" content="{{ .Permalink | absURL }}" />
<meta name="twitter:image:src" content="{{ .Permalink | absURL }}" />
{{- else }}
{{ "<!-- image -->" | safeHTML }}
<meta itemprop="image" content='{{ $staticIcon }}' />
<meta property="og:image" content='{{ $staticIcon }}' />
<meta name="twitter:image" content='{{ $staticIcon }}' />
<meta name="twitter:image:src" content='{{ $staticIcon }}' />
<meta property="og:image" itemprop="image" content="{{ $staticIcon }}" />
<meta name="twitter:image" content="{{ $staticIcon }}" />
<meta name="twitter:image:src" content="{{ $staticIcon }}" />
{{- end -}}
{{/*=== author ===*/}}
{{/*=== extra params? ===*/}}
{{- with .Params.audio }}<meta property="og:audio" content="{{ . }}" />{{ end }}
{{- with .Params.locale }}<meta property="og:locale" content="{{ . }}" />{{ end }}
{{- with .Params.videos }}{{- range . }}
<meta property="og:video" content="{{ . | absURL }}" />
{{ end }}{{ end }}
{{/*=== article ===*/}}
{{ with or .Params.author .Site.Params.author -}}
{{ "<!-- author -->" | safeHTML }}
<meta property="article:publisher" content="{{ . }}" />
<meta property="og:article:author" content="{{ . }}" />
<meta property="article:author" content="{{ . }}" />
<meta name="author" content="{{ . }}" />
{{- end -}}
{{/*=== published and updated ===*/}}
{{- "<!-- time -->" | safeHTML }}
{{ with .Date }}
<meta property="og:article:published_time" content={{ .Format "2006-01-02T15:04:05Z0700" | safeHTML }} />
<meta property="article:published_time" content={{ .Format "2006-01-02T15:04:05Z0700" | safeHTML }} />
<meta name="author" property="article:author" content="{{ . }}" />
{{- end }}
<meta property="article:publisher" content="{{ .Site.BaseURL }}" />
{{ "<!-- time -->" | safeHTML }}
{{ with .Date -}}
<meta property="article:published_time" itemprop="datePublished" content={{ .Format "2006-01-02T03:04:05Z" | safeHTML }} />
{{ end -}}
{{ with .Lastmod -}}
<meta property="og:updated_time" content={{ .Format "2006-01-02T15:04:05Z0700" | safeHTML }} />
<meta property="article:modified_time" itemprop="dateModified" content={{ .Format "2006-01-02T03:04:05Z" | safeHTML }} />
{{ end -}}
{{/*=== section and keywords ===*/}}
{{- "<!-- keywords -->" | safeHTML }}
{{- with.Params.category -}}
<meta name="news_keywords" content="{{ . }}" />
{{ with.Params.category -}}
<meta property="article:section" content="{{ . }}" />
{{- end -}}
{{- with .Params.tags }}
<meta name="keywords" content='{{ delimit . " "}}'>
<meta property="article:tag" itemprop="keywords" name="keywords" content='{{ delimit . " "}}' />
{{- end -}}
{{- if isset .Params "date" -}}
{{- if isset .Params "date" }}
{{ "<!-- article metadata -->" | safeHTML }}
<meta property="og:type" content="article" />
<meta itemprop="wordCount" content="{{ .WordCount }}" />
<script defer type="application/ld+json">
{
"@context": "http://schema.org",
@ -87,21 +94,23 @@
"headline": {{ $title }},
"author": {
"@type": "Person",
"name": "{{ or .Params.author .Site.Params.author }}"
"name": {{ or .Params.author .Site.Params.author }},
"url": {{ .Site.BaseURL }}
},
"datePublished": "{{ .Date.Format "2006-01-02" }}",
"description": {{ or .Description .Summary }},
"datePublished": {{ .Date.UTC.Format "2006-01-02T03:04:05Z" }},
"description": {{ (or .Description .Summary) | plainify }},
"wordCount": {{ .WordCount }},
"mainEntityOfPage": "True",
"dateModified": "{{ .Lastmod.Format "2006-01-02" }}",
"mainEntityOfPage": {{.Permalink}},
"dateModified": "{{ .Lastmod.UTC.Format "2006-01-02T03:04:05Z" }}",
"image": {
"@type": "ImageObject",
"url": "{{ with or $cover $icon }}{{ .Permalink | absURL }}{{ end }}"
"url": {{ with or $cover $icon }}{{ .Permalink | absURL }}{{ end }}
},
"publisher": {
"@type": "Person",
"name": "{{ or .Params.author .Site.Params.author .Site.Title }}",
"logo": {
"@type": "WebSite",
"name": {{ .Site.Title }},
"url": {{ .Site.BaseURL }},
"image": {
"@type": "ImageObject",
"url": {{with $icon}}{{.Permalink}}{{else}}{{$staticIcon}}{{end}}
}
@ -109,31 +118,39 @@
}
</script>
{{- else }}
{{- else }}
{{ "<!-- webpage metadata -->" | safeHTML }}
<meta property="og:type" content="website" />
<script defer type="application/ld+json">
{
"@context": "http://schema.org",
"@type": "WebSite",
"url": {{ .Permalink }},
"name": "{{ .Site.Title }}",
"logo": {{with $icon}}{{.Permalink}}{{else}}{{$staticIcon}}{{end}}
{
"@context": "http://schema.org",
"@type": "WebPage",
"name": {{ .Title }},
"url": {{ .Permalink }},
"description": {{ (or .Description .Summary) | plainify }},
"image": {
"@type": "ImageObject",
"url": {{with $icon}}{{.Permalink}}{{else}}{{$staticIcon}}{{end}}
}
}
</script>
{{- end -}}
{{/* auxiliary info */}}
{{ "<!-- site presentation -->" | safeHTML }}
{{ with $icon }}
<link rel="shortcut icon" href='{{ .Permalink }}' sizes="{{.Width}}x{{.Height}}">
<link rel="shortcut icon" href='{{ .Permalink }}' sizes="{{.Width}}x{{.Height}}" />
{{- else -}}
<link rel="shortcut icon" href='{{ $staticIcon }}' sizes="512x512">
<link rel="shortcut icon" href='{{ $staticIcon }}' sizes="512x512" />
{{- end }}
<meta name="theme-color" content="#ffffff" />
<meta name="msapplication-TileColor" content="#ffffff" />
<link rel="sitemap" type="application/xml" title="Sitemap" href="{{ .Site.BaseURL }}sitemap.xml" />
{{ with .OutputFormats.Get "RSS" -}}
<link href="{{ .Permalink }}" rel="feed alternate" type="application/rss+xml" title="{{ $.Site.Title }}" />
{{- end }}
{{- end -}}
{{/* robots */}}
{{ "<!-- robots -->" | safeHTML }}
<meta name="robots" content="index,follow" />
<meta name="googlebot" content="index,follow" />