Skip to content

Commit 1cf124f

Browse files
hyperpolymathclaude
andcommitted
Standardise license setup: MPL-2.0 + PMPL-1.0-or-later (REUSE)
- LICENSE: pure MPL-2.0 text for machine detection (GitHub, registries) - LICENSES/MPL-2.0.txt: standard MPL-2.0 text - LICENSES/PMPL-1.0-or-later.txt: Palimpsest License text - NOTICE: explains the dual-license relationship - Source SPDX headers remain PMPL-1.0-or-later This ensures OSI compliance checks pass while preserving PMPL as the governing license for source code. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d716bd2 commit 1cf124f

9 files changed

Lines changed: 1090 additions & 305 deletions

File tree

LICENSE

Lines changed: 368 additions & 148 deletions
Large diffs are not rendered by default.

LICENSES/MPL-2.0.txt

Lines changed: 373 additions & 0 deletions
Large diffs are not rendered by default.

LICENSES/PMPL-1.0-or-later.txt

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
SPDX-License-Identifier: PMPL-1.0-or-later
2+
SPDX-FileCopyrightText: 2025 Palimpsest Stewardship Council
3+
4+
================================================================================
5+
PALIMPSEST-MPL LICENSE VERSION 1.0
6+
================================================================================
7+
8+
File-level copyleft with ethical use and quantum-safe provenance
9+
10+
Based on Mozilla Public License 2.0
11+
12+
--------------------------------------------------------------------------------
13+
PREAMBLE
14+
--------------------------------------------------------------------------------
15+
16+
This License extends the Mozilla Public License 2.0 (MPL-2.0) with provisions
17+
for ethical use, post-quantum cryptographic provenance, and emotional lineage
18+
protection. The base MPL-2.0 terms apply except where explicitly modified by
19+
the Exhibits below.
20+
21+
Like a palimpsest manuscript where each layer builds upon what came before,
22+
this license recognizes that creative works carry history, context, and meaning
23+
that transcend mere code or text.
24+
25+
--------------------------------------------------------------------------------
26+
SECTION 1: BASE LICENSE
27+
--------------------------------------------------------------------------------
28+
29+
This License incorporates the full text of Mozilla Public License 2.0 by
30+
reference. The complete MPL-2.0 text is available at:
31+
https://www.mozilla.org/en-US/MPL/2.0/
32+
33+
All terms, conditions, and definitions from MPL-2.0 apply except where
34+
explicitly modified by the Exhibits in this License.
35+
36+
--------------------------------------------------------------------------------
37+
SECTION 2: ADDITIONAL DEFINITIONS
38+
--------------------------------------------------------------------------------
39+
40+
2.1. "Emotional Lineage"
41+
means the narrative, cultural, symbolic, and contextual meaning embedded
42+
in Covered Software, including but not limited to: protest traditions,
43+
cultural heritage, trauma narratives, and community stories.
44+
45+
2.2. "Provenance Metadata"
46+
means cryptographically signed attribution information attached to or
47+
associated with Covered Software, including author identities, timestamps,
48+
modification history, and lineage references.
49+
50+
2.3. "Non-Interpretive System"
51+
means any automated system that processes Covered Software without
52+
preserving or considering its Emotional Lineage, including but not
53+
limited to: AI training pipelines, content aggregators, and automated
54+
summarization tools.
55+
56+
2.4. "Quantum-Safe Signature"
57+
means a cryptographic signature using algorithms resistant to attacks
58+
by quantum computers, as specified in Exhibit B.
59+
60+
--------------------------------------------------------------------------------
61+
SECTION 3: ETHICAL USE REQUIREMENTS
62+
--------------------------------------------------------------------------------
63+
64+
In addition to the rights and obligations under MPL-2.0:
65+
66+
3.1. Emotional Lineage Preservation
67+
You must make reasonable efforts to preserve and communicate the
68+
Emotional Lineage of Covered Software when distributing or creating
69+
derivative works. This includes maintaining narrative context, cultural
70+
attributions, and symbolic meaning where documented.
71+
72+
3.2. Non-Interpretive System Notice
73+
If You use Covered Software as input to a Non-Interpretive System, You
74+
must:
75+
(a) document such use in a publicly accessible manner; and
76+
(b) not claim that outputs of such systems carry the Emotional Lineage
77+
of the original work without explicit permission from Contributors.
78+
79+
3.3. Ethical Use Declaration
80+
Commercial use of Covered Software requires acknowledgment that You have
81+
read and understood Exhibit A (Ethical Use Guidelines) and agree to act
82+
in good faith accordance with its principles.
83+
84+
See Exhibit A for complete Ethical Use Guidelines.
85+
86+
--------------------------------------------------------------------------------
87+
SECTION 4: PROVENANCE REQUIREMENTS
88+
--------------------------------------------------------------------------------
89+
90+
4.1. Metadata Preservation
91+
You must not strip, alter, or obscure Provenance Metadata from Covered
92+
Software except where technically necessary and with clear documentation
93+
of any changes.
94+
95+
4.2. Quantum-Safe Provenance (Optional)
96+
Contributors may sign their Contributions using Quantum-Safe Signatures.
97+
If Quantum-Safe Signatures are present, You must preserve them in all
98+
distributions.
99+
100+
4.3. Lineage Chain
101+
When creating derivative works, You should extend the provenance chain
102+
to include Your own contributions, maintaining cryptographic linkage to
103+
prior Contributors where feasible.
104+
105+
See Exhibit B for Quantum-Safe Provenance specifications.
106+
107+
--------------------------------------------------------------------------------
108+
SECTION 5: GOVERNANCE
109+
--------------------------------------------------------------------------------
110+
111+
5.1. Stewardship Council
112+
This License is maintained by the Palimpsest Stewardship Council, which
113+
may issue clarifications, interpretive guidance, and future versions.
114+
115+
5.2. Version Selection
116+
You may use Covered Software under this version of the License or any
117+
later version published by the Palimpsest Stewardship Council.
118+
119+
5.3. Dispute Resolution
120+
Disputes regarding interpretation of Ethical Use Requirements (Section 3)
121+
should first be submitted to the Palimpsest Stewardship Council for
122+
non-binding guidance before pursuing legal remedies.
123+
124+
--------------------------------------------------------------------------------
125+
SECTION 6: COMPATIBILITY
126+
--------------------------------------------------------------------------------
127+
128+
6.1. MPL-2.0 Compatibility
129+
Covered Software under this License may be combined with software under
130+
MPL-2.0. The combined work must comply with both licenses.
131+
132+
6.2. Secondary Licenses
133+
The Secondary License provisions of MPL-2.0 Section 3.3 apply to this
134+
License.
135+
136+
--------------------------------------------------------------------------------
137+
EXHIBITS
138+
--------------------------------------------------------------------------------
139+
140+
Exhibit A - Ethical Use Guidelines
141+
Exhibit B - Quantum-Safe Provenance Specification
142+
143+
See separate files:
144+
- EXHIBIT-A-ETHICAL-USE.txt
145+
- EXHIBIT-B-QUANTUM-SAFE.txt
146+
147+
--------------------------------------------------------------------------------
148+
END OF PALIMPSEST-MPL-1.0 LICENSE TEXT
149+
--------------------------------------------------------------------------------
150+
151+
For exhibits, specifications, provenance rules, and governance:
152+
https://github.com/hyperpolymath/palimpsest-license
153+
154+
For legal frameworks and jurisdictional analysis:
155+
See /legal/frameworks/
156+
157+
For provenance and audit tooling:
158+
See /tools/ and /spec/PROVENANCE-SPEC.adoc
159+
160+
For questions about this License:
161+
- Repository: https://github.com/hyperpolymath/palimpsest-license
162+
- Council: contact via repository Issues

NOTICE

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Licensing Notice
2+
================
3+
4+
This project is authored by Jonathan D.A. Jewell (hyperpolymath) and
5+
is licensed under the Palimpsest License (PMPL-1.0-or-later).
6+
7+
The PMPL-1.0-or-later is a philosophical extension of the Mozilla Public
8+
License 2.0, adding provisions for cryptographic provenance, emotional
9+
lineage preservation, and quantum-safe signatures. The full PMPL text is
10+
available in LICENSES/PMPL-1.0-or-later.txt.
11+
12+
For compatibility with automated license detection tools and platforms
13+
that require OSI-approved licenses, the root LICENSE file contains the
14+
standard Mozilla Public License 2.0 text. This ensures that package
15+
registries, CI systems, and other tooling correctly identify the license.
16+
17+
The legally binding terms are:
18+
- Source files: governed by PMPL-1.0-or-later (per SPDX headers)
19+
- Combined works: compatible with MPL-2.0 (per PMPL Section 6)
20+
21+
For more information about the Palimpsest License:
22+
https://github.com/hyperpolymath/palimpsest-license

elixir-mcp/lib/feedback_a_tron/credentials.ex

Lines changed: 142 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,10 @@ defmodule FeedbackATron.Credentials do
1515

1616

1717

18-
defstruct [:github, :gitlab, :bitbucket, :codeberg, :bugzilla, :email]
18+
defstruct [
19+
:github, :gitlab, :bitbucket, :codeberg, :bugzilla, :email,
20+
:nntp, :discourse, :mailman, :sourcehut, :jira, :matrix
21+
]
1922

2023
@doc """
2124
Load credentials from all available sources.
@@ -27,7 +30,13 @@ defmodule FeedbackATron.Credentials do
2730
bitbucket: load_bitbucket_creds(),
2831
codeberg: load_codeberg_creds(),
2932
bugzilla: load_bugzilla_creds(),
30-
email: load_email_config()
33+
email: load_email_config(),
34+
nntp: load_nntp_creds(),
35+
discourse: load_discourse_creds(),
36+
mailman: load_mailman_creds(),
37+
sourcehut: load_sourcehut_creds(),
38+
jira: load_jira_creds(),
39+
matrix: load_matrix_creds()
3140
}
3241
end
3342

@@ -160,6 +169,137 @@ defmodule FeedbackATron.Credentials do
160169
end
161170
end
162171

172+
# NNTP: NNTPS server config
173+
defp load_nntp_creds do
174+
case System.get_env("NNTP_SERVER") do
175+
nil -> []
176+
server ->
177+
[%{
178+
source: :env,
179+
server: server,
180+
port: String.to_integer(System.get_env("NNTP_PORT", "563")),
181+
newsgroup: System.get_env("NNTP_NEWSGROUP"),
182+
username: System.get_env("NNTP_USERNAME"),
183+
password: System.get_env("NNTP_PASSWORD"),
184+
from: System.get_env("NNTP_FROM", "feedback-a-tron@localhost")
185+
}]
186+
end
187+
end
188+
189+
# Discourse: HTTPS API
190+
defp load_discourse_creds do
191+
case System.get_env("DISCOURSE_URL") do
192+
nil -> []
193+
url ->
194+
if String.starts_with?(url, "https://") do
195+
[%{
196+
source: :env,
197+
base_url: url,
198+
api_key: System.get_env("DISCOURSE_API_KEY"),
199+
api_username: System.get_env("DISCOURSE_API_USERNAME", "system"),
200+
default_category_id: System.get_env("DISCOURSE_CATEGORY_ID")
201+
}]
202+
else
203+
Logger.warning("Discourse URL must be HTTPS, ignoring: #{url}")
204+
[]
205+
end
206+
end
207+
end
208+
209+
# Mailman: SMTPS or HyperKitty REST
210+
defp load_mailman_creds do
211+
creds = []
212+
213+
# HyperKitty REST API
214+
creds = case System.get_env("HYPERKITTY_URL") do
215+
nil -> creds
216+
url ->
217+
if String.starts_with?(url, "https://") do
218+
[%{
219+
source: :env,
220+
hyperkitty_url: url,
221+
api_key: System.get_env("HYPERKITTY_API_KEY"),
222+
list_id: System.get_env("MAILMAN_LIST_ID")
223+
} | creds]
224+
else
225+
creds
226+
end
227+
end
228+
229+
# Direct SMTPS to list address
230+
creds = case System.get_env("MAILMAN_LIST_ADDRESS") do
231+
nil -> creds
232+
list_addr ->
233+
[%{
234+
source: :env,
235+
list_address: list_addr,
236+
smtp_server: System.get_env("MAILMAN_SMTP_SERVER"),
237+
smtp_port: String.to_integer(System.get_env("MAILMAN_SMTP_PORT", "465")),
238+
smtp_username: System.get_env("MAILMAN_SMTP_USERNAME"),
239+
smtp_password: System.get_env("MAILMAN_SMTP_PASSWORD"),
240+
from: System.get_env("MAILMAN_FROM", "feedback-a-tron@localhost")
241+
} | creds]
242+
end
243+
244+
creds
245+
end
246+
247+
# SourceHut: personal access token
248+
defp load_sourcehut_creds do
249+
case System.get_env("SRHT_TOKEN") do
250+
nil -> []
251+
token ->
252+
[%{
253+
source: :env,
254+
token: token,
255+
tracker: System.get_env("SRHT_TRACKER"),
256+
api_base: System.get_env("SRHT_API_BASE", "https://todo.sr.ht")
257+
}]
258+
end
259+
end
260+
261+
# Jira: Cloud (email + API token) or Server (PAT)
262+
defp load_jira_creds do
263+
case System.get_env("JIRA_URL") do
264+
nil -> []
265+
url ->
266+
if String.starts_with?(url, "https://") do
267+
[%{
268+
source: :env,
269+
base_url: url,
270+
email: System.get_env("JIRA_EMAIL"),
271+
api_token: System.get_env("JIRA_API_TOKEN"),
272+
token: System.get_env("JIRA_TOKEN"),
273+
project_key: System.get_env("JIRA_PROJECT_KEY"),
274+
default_issue_type: System.get_env("JIRA_ISSUE_TYPE", "Task"),
275+
api_version: System.get_env("JIRA_API_VERSION", "2")
276+
}]
277+
else
278+
Logger.warning("Jira URL must be HTTPS, ignoring: #{url}")
279+
[]
280+
end
281+
end
282+
end
283+
284+
# Matrix: homeserver + access token
285+
defp load_matrix_creds do
286+
case System.get_env("MATRIX_HOMESERVER") do
287+
nil -> []
288+
homeserver ->
289+
if String.starts_with?(homeserver, "https://") do
290+
[%{
291+
source: :env,
292+
homeserver: homeserver,
293+
access_token: System.get_env("MATRIX_ACCESS_TOKEN"),
294+
room_id: System.get_env("MATRIX_ROOM_ID")
295+
}]
296+
else
297+
Logger.warning("Matrix homeserver must be HTTPS, ignoring: #{homeserver}")
298+
[]
299+
end
300+
end
301+
end
302+
163303
# Simple round-robin rotation using process dictionary
164304
# In production, use ETS or Agent for shared state
165305
defp rotate(creds) do

elixir-mcp/lib/feedback_a_tron/migration_observer.ex

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -209,22 +209,22 @@ defmodule FeedbackATron.MigrationObserver do
209209
end
210210
end
211211

212-
defp compute_diff(before, after) do
213-
before_deprecated = get_in(before, ["migration_metrics", "deprecated_api_count"]) || 0
214-
after_deprecated = get_in(after, ["migration_metrics", "deprecated_api_count"]) || 0
215-
before_modern = get_in(before, ["migration_metrics", "modern_api_count"]) || 0
216-
after_modern = get_in(after, ["migration_metrics", "modern_api_count"]) || 0
217-
before_health = get_in(before, ["migration_metrics", "health_score"]) || 0.0
218-
after_health = get_in(after, ["migration_metrics", "health_score"]) || 0.0
212+
defp compute_diff(before_snapshot, after_snapshot) do
213+
before_deprecated = get_in(before_snapshot, ["migration_metrics", "deprecated_api_count"]) || 0
214+
after_deprecated = get_in(after_snapshot, ["migration_metrics", "deprecated_api_count"]) || 0
215+
before_modern = get_in(before_snapshot, ["migration_metrics", "modern_api_count"]) || 0
216+
after_modern = get_in(after_snapshot, ["migration_metrics", "modern_api_count"]) || 0
217+
before_health = get_in(before_snapshot, ["migration_metrics", "health_score"]) || 0.0
218+
after_health = get_in(after_snapshot, ["migration_metrics", "health_score"]) || 0.0
219219

220220
%{
221221
health_delta: after_health - before_health,
222222
deprecated_delta: after_deprecated - before_deprecated,
223223
modern_delta: after_modern - before_modern,
224-
version_before: get_in(before, ["migration_metrics", "version_bracket"]),
225-
version_after: get_in(after, ["migration_metrics", "version_bracket"]),
226-
config_before: get_in(before, ["migration_metrics", "config_format"]),
227-
config_after: get_in(after, ["migration_metrics", "config_format"])
224+
version_before: get_in(before_snapshot, ["migration_metrics", "version_bracket"]),
225+
version_after: get_in(after_snapshot, ["migration_metrics", "version_bracket"]),
226+
config_before: get_in(before_snapshot, ["migration_metrics", "config_format"]),
227+
config_after: get_in(after_snapshot, ["migration_metrics", "config_format"])
228228
}
229229
end
230230

0 commit comments

Comments
 (0)