diff --git a/MANIFEST.yaml b/MANIFEST.yaml index 9f14fb4c..38ec2e60 100644 --- a/MANIFEST.yaml +++ b/MANIFEST.yaml @@ -813,7 +813,7 @@ files: - path: scripts/lib/obligation-first.js role: tooling - hash: sha256:868310c404cbd0eab87e045541de95c23a2b9e67194495bc0efa130c1e3319fd + hash: sha256:a29612a4039a612edbcfc0a55c70a6cb7668645b87a2b64b9d1d49cadb3a9b0d note: scripts/lib/obligation-first.js - path: scripts/lib/temporal-status.js @@ -1038,7 +1038,7 @@ files: - path: tests/source-admission.test.js role: code - hash: sha256:0d13f401800e2b95eea010905c6eea6c1c8081ed10d518dc8836931b5c4a6106 + hash: sha256:10be9419f4d32940c9988fed0e13edd48fdb0d81b456989b80794d89b6b0c163 note: Source admission policy and producer-gate regressions - path: tests/publication-state.test.js diff --git a/docs/MANIFEST.yaml b/docs/MANIFEST.yaml index 9f14fb4c..38ec2e60 100644 --- a/docs/MANIFEST.yaml +++ b/docs/MANIFEST.yaml @@ -813,7 +813,7 @@ files: - path: scripts/lib/obligation-first.js role: tooling - hash: sha256:868310c404cbd0eab87e045541de95c23a2b9e67194495bc0efa130c1e3319fd + hash: sha256:a29612a4039a612edbcfc0a55c70a6cb7668645b87a2b64b9d1d49cadb3a9b0d note: scripts/lib/obligation-first.js - path: scripts/lib/temporal-status.js @@ -1038,7 +1038,7 @@ files: - path: tests/source-admission.test.js role: code - hash: sha256:0d13f401800e2b95eea010905c6eea6c1c8081ed10d518dc8836931b5c4a6106 + hash: sha256:10be9419f4d32940c9988fed0e13edd48fdb0d81b456989b80794d89b6b0c163 note: Source admission policy and producer-gate regressions - path: tests/publication-state.test.js diff --git a/docs/api/v1/of/instruments.json b/docs/api/v1/of/instruments.json index a6aeded7..69b7ed2c 100644 --- a/docs/api/v1/of/instruments.json +++ b/docs/api/v1/of/instruments.json @@ -994,7 +994,7 @@ "territorial_scope": [ "us-ut" ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/api/v1/of/obligations.json b/docs/api/v1/of/obligations.json index f673b349..de39156b 100644 --- a/docs/api/v1/of/obligations.json +++ b/docs/api/v1/of/obligations.json @@ -29,8 +29,8 @@ "us-ut" ] }, - "source": "https://commerce.utah.gov/ai/", - "source_locator": "Utah Code §13-72a-203", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", + "source_locator": "First-Session Disclosure (§13-72a-203)", "evidence_type": "reviewed-source-reference", "verified": "2026-04-18", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/api/v1/of/parties.json b/docs/api/v1/of/parties.json index 8675d051..eff651be 100644 --- a/docs/api/v1/of/parties.json +++ b/docs/api/v1/of/parties.json @@ -21,7 +21,7 @@ "roles": [ "requesting_party" ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", @@ -73,7 +73,7 @@ "roles": [ "interpreting_authority" ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/api/v1/of/records/us-ut-oaip-jia-2026-001-publedge-illustrative-requesting-party.json b/docs/api/v1/of/records/us-ut-oaip-jia-2026-001-publedge-illustrative-requesting-party.json index b686b635..591c8fd6 100644 --- a/docs/api/v1/of/records/us-ut-oaip-jia-2026-001-publedge-illustrative-requesting-party.json +++ b/docs/api/v1/of/records/us-ut-oaip-jia-2026-001-publedge-illustrative-requesting-party.json @@ -17,7 +17,7 @@ "roles": [ "requesting_party" ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/api/v1/of/records/us-ut-oaip-jia-2026-001-utah-oaip.json b/docs/api/v1/of/records/us-ut-oaip-jia-2026-001-utah-oaip.json index 5fa7d3f2..74451059 100644 --- a/docs/api/v1/of/records/us-ut-oaip-jia-2026-001-utah-oaip.json +++ b/docs/api/v1/of/records/us-ut-oaip-jia-2026-001-utah-oaip.json @@ -17,7 +17,7 @@ "roles": [ "interpreting_authority" ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/api/v1/of/records/us-ut-oaip-jia-2026-001.json b/docs/api/v1/of/records/us-ut-oaip-jia-2026-001.json index 9e54e820..96093035 100644 --- a/docs/api/v1/of/records/us-ut-oaip-jia-2026-001.json +++ b/docs/api/v1/of/records/us-ut-oaip-jia-2026-001.json @@ -44,7 +44,7 @@ "territorial_scope": [ "us-ut" ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/api/v1/of/records/utah-mental-health-chatbot-disclosure-2026q2-first-session-disclose-genai-on-first-session.json b/docs/api/v1/of/records/utah-mental-health-chatbot-disclosure-2026q2-first-session-disclose-genai-on-first-session.json index 2357d56a..32e49f2a 100644 --- a/docs/api/v1/of/records/utah-mental-health-chatbot-disclosure-2026q2-first-session-disclose-genai-on-first-session.json +++ b/docs/api/v1/of/records/utah-mental-health-chatbot-disclosure-2026q2-first-session-disclose-genai-on-first-session.json @@ -25,8 +25,8 @@ "us-ut" ] }, - "source": "https://commerce.utah.gov/ai/", - "source_locator": "Utah Code §13-72a-203", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", + "source_locator": "First-Session Disclosure (§13-72a-203)", "evidence_type": "reviewed-source-reference", "verified": "2026-04-18", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/api/v1/of/records/utah-mental-health-chatbot-disclosure-2026q2-first-session.json b/docs/api/v1/of/records/utah-mental-health-chatbot-disclosure-2026q2-first-session.json index f8fc146b..b4c64989 100644 --- a/docs/api/v1/of/records/utah-mental-health-chatbot-disclosure-2026q2-first-session.json +++ b/docs/api/v1/of/records/utah-mental-health-chatbot-disclosure-2026q2-first-session.json @@ -29,8 +29,8 @@ "us-ut" ] }, - "source": "https://commerce.utah.gov/ai/", - "source_locator": "Utah Code §13-72a-203", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", + "source_locator": "First-Session Disclosure (§13-72a-203)", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/api/v1/of/terms.json b/docs/api/v1/of/terms.json index e53d0dad..e03b099e 100644 --- a/docs/api/v1/of/terms.json +++ b/docs/api/v1/of/terms.json @@ -33,8 +33,8 @@ "us-ut" ] }, - "source": "https://commerce.utah.gov/ai/", - "source_locator": "Utah Code §13-72a-203", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", + "source_locator": "First-Session Disclosure (§13-72a-203)", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/instrument/us-ut-oaip-jia-2026-001.json b/docs/instrument/us-ut-oaip-jia-2026-001.json index 9e54e820..96093035 100644 --- a/docs/instrument/us-ut-oaip-jia-2026-001.json +++ b/docs/instrument/us-ut-oaip-jia-2026-001.json @@ -44,7 +44,7 @@ "territorial_scope": [ "us-ut" ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/obligation/utah-mental-health-chatbot-disclosure-2026q2-first-session-disclose-genai-on-first-session.json b/docs/obligation/utah-mental-health-chatbot-disclosure-2026q2-first-session-disclose-genai-on-first-session.json index 2357d56a..32e49f2a 100644 --- a/docs/obligation/utah-mental-health-chatbot-disclosure-2026q2-first-session-disclose-genai-on-first-session.json +++ b/docs/obligation/utah-mental-health-chatbot-disclosure-2026q2-first-session-disclose-genai-on-first-session.json @@ -25,8 +25,8 @@ "us-ut" ] }, - "source": "https://commerce.utah.gov/ai/", - "source_locator": "Utah Code §13-72a-203", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", + "source_locator": "First-Session Disclosure (§13-72a-203)", "evidence_type": "reviewed-source-reference", "verified": "2026-04-18", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/party/us-ut-oaip-jia-2026-001-publedge-illustrative-requesting-party.json b/docs/party/us-ut-oaip-jia-2026-001-publedge-illustrative-requesting-party.json index b686b635..591c8fd6 100644 --- a/docs/party/us-ut-oaip-jia-2026-001-publedge-illustrative-requesting-party.json +++ b/docs/party/us-ut-oaip-jia-2026-001-publedge-illustrative-requesting-party.json @@ -17,7 +17,7 @@ "roles": [ "requesting_party" ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/party/us-ut-oaip-jia-2026-001-utah-oaip.json b/docs/party/us-ut-oaip-jia-2026-001-utah-oaip.json index 5fa7d3f2..74451059 100644 --- a/docs/party/us-ut-oaip-jia-2026-001-utah-oaip.json +++ b/docs/party/us-ut-oaip-jia-2026-001-utah-oaip.json @@ -17,7 +17,7 @@ "roles": [ "interpreting_authority" ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", diff --git a/docs/term/utah-mental-health-chatbot-disclosure-2026q2-first-session.json b/docs/term/utah-mental-health-chatbot-disclosure-2026q2-first-session.json index f8fc146b..b4c64989 100644 --- a/docs/term/utah-mental-health-chatbot-disclosure-2026q2-first-session.json +++ b/docs/term/utah-mental-health-chatbot-disclosure-2026q2-first-session.json @@ -29,8 +29,8 @@ "us-ut" ] }, - "source": "https://commerce.utah.gov/ai/", - "source_locator": "Utah Code §13-72a-203", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", + "source_locator": "First-Session Disclosure (§13-72a-203)", "evidence_type": "reviewed-source-reference", "verified": "2026-09-23", "asserted_by_adopter": "https://publedge.org/", diff --git a/scripts/lib/obligation-first.js b/scripts/lib/obligation-first.js index 553d2e95..6a762fb9 100644 --- a/scripts/lib/obligation-first.js +++ b/scripts/lib/obligation-first.js @@ -194,6 +194,23 @@ function provenance(config, source, locator, verified, citation) { }); } +// A PubLedge original draft is published by PubLedge, not by the authority it +// names. Its text's provenance is the draft record itself; the statute it +// interprets stays linked through source-owned anchors, and the locator names +// the draft's own section rather than a statutory section. +function isOriginalDraft(container) { + return container?.source === 'publedge-original-draft'; +} + +function recordSource(config, container) { + if (!isOriginalDraft(container)) return container?.official_url; + return container._canonicalPath ? `${siteBase(config)}/${container._canonicalPath}` : undefined; +} + +function recordLocator(container, provision, mapping) { + return isOriginalDraft(container) ? mapping.source_heading : provision.sections || mapping.source_heading; +} + function partyId(container, party, index) { return `${container.id}-${slugify(party.name || party.role || `party-${index + 1}`)}`; } @@ -219,7 +236,7 @@ function buildPartyRecords(config, data) { party_kind: kind, entity: kind === 'organization' ? { '@type': 'gist:Organization', name: party.name } : undefined, roles: party.role ? [party.role] : undefined, - ...provenance(config, container.official_url, undefined, container.last_verified, instrumentCitation(container)) + ...provenance(config, recordSource(config, container), undefined, container.last_verified, instrumentCitation(container)) }), [container._evidence_input])); } } @@ -295,7 +312,7 @@ function buildInstrumentRecords(config, data, determinations) { jurisdiction: typedJurisdiction(container.jurisdiction), territorial_scope: container.jurisdiction ? [container.jurisdiction] : undefined, citation: instrumentCitation(container), - ...provenance(config, container.official_url, undefined, container.last_verified, instrumentCitation(container)), + ...provenance(config, recordSource(config, container), undefined, container.last_verified, instrumentCitation(container)), 'pub:status': container.status, 'pub:editorial_status': container.editorial_status, 'pub:canonical_url': container._canonicalPath ? `${siteBase(config)}/${container._canonicalPath}` : undefined @@ -329,7 +346,7 @@ function buildTermRecords(config, data) { enforcement_status: container?.enforcement_status || enforcementStatus({ status: sourceStatus, type: container?.type }, force), effective: /^\d{4}-\d{2}-\d{2}$/.test(provision.effective || '') ? provision.effective : undefined, jurisdiction: typedJurisdiction(container?.jurisdiction), - ...provenance(config, container?.official_url, provision.sections || mapping.source_heading, provision.verified || container?.last_verified, instrumentCitation(container || {})), + ...provenance(config, recordSource(config, container), recordLocator(container, provision, mapping), provision.verified || container?.last_verified, instrumentCitation(container || {})), 'pub:source_heading': mapping.source_heading, 'pub:source_file': mapping.source_file }), [container._evidence_input, mapping._evidence_input]); @@ -367,7 +384,7 @@ function buildObligationRecords(config, data) { operative_status: (draftCreated ? undefined : primary.operative_status) || container?.operative_status || operativeStatus(lifecycle, force), enforcement_status: (draftCreated ? undefined : primary.enforcement_status) || container?.enforcement_status || enforcementStatus({ status: lifecycle, type: container?.type }, force), jurisdiction: typedJurisdiction(container?.jurisdiction), - ...provenance(config, container?.official_url, provision.sections || mapping.source_heading, primary.last_verified || provision.verified || container?.last_verified, instrumentCitation(container || {})), + ...provenance(config, recordSource(config, container), recordLocator(container, provision, mapping), primary.last_verified || provision.verified || container?.last_verified, instrumentCitation(container || {})), 'pub:primary_id': obligationId, 'pub:group': primary.group || undefined, 'pub:status': primary.status || undefined, diff --git a/tests/fixtures/of-contract-fingerprint.json b/tests/fixtures/of-contract-fingerprint.json index 178f39e3..059ca61b 100644 --- a/tests/fixtures/of-contract-fingerprint.json +++ b/tests/fixtures/of-contract-fingerprint.json @@ -3695,7 +3695,7 @@ "Lawyer review and authority sign-off remain pending; the draft is not issued.", "The EveryAILaw amended-stack correspondence for the SB 149 slug was not compared field by field." ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "source_review_conflicts": null }, "https://publedge.org/instrument/us-ut-oaip-rma-2024-001.json": { @@ -7346,8 +7346,8 @@ "The obligation id and name still say 'first session'; renaming the id is a separate schema decision.", "last_verified renewal requires a separate human review receipt." ], - "source": "https://commerce.utah.gov/ai/", - "source_locator": "Utah Code §13-72a-203", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", + "source_locator": "First-Session Disclosure (§13-72a-203)", "source_review_conflicts": null }, "https://publedge.org/party/us-ut-oaip-jia-2026-001-publedge-illustrative-requesting-party.json": { @@ -7380,7 +7380,7 @@ "Lawyer review and authority sign-off remain pending; the draft is not issued.", "The EveryAILaw amended-stack correspondence for the SB 149 slug was not compared field by field." ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "source_review_conflicts": null }, "https://publedge.org/party/us-ut-oaip-jia-2026-001-utah-oaip.json": { @@ -7413,7 +7413,7 @@ "Lawyer review and authority sign-off remain pending; the draft is not issued.", "The EveryAILaw amended-stack correspondence for the SB 149 slug was not compared field by field." ], - "source": "https://commerce.utah.gov/ai/", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", "source_review_conflicts": null }, "https://publedge.org/party/us-ut-oaip-rma-2024-001-elizachat-inc.json": { @@ -8662,8 +8662,8 @@ "The sb149-learning-lab-and-ai-defense and hb452-mental-health-chatbot-stack mappings are kept and qualified, not removed; whether to remap them is a human decision.", "The disclose-genai-on-first-session obligation id and name still say 'first session'; its text was corrected in a separate receipt." ], - "source": "https://commerce.utah.gov/ai/", - "source_locator": "Utah Code §13-72a-203", + "source": "https://publedge.org/us/utah/oaip/jia/2026-001/", + "source_locator": "First-Session Disclosure (§13-72a-203)", "source_review_conflicts": null } }, diff --git a/tests/source-admission.test.js b/tests/source-admission.test.js index aee1e927..45e67e47 100644 --- a/tests/source-admission.test.js +++ b/tests/source-admission.test.js @@ -450,3 +450,28 @@ test('an obligation created only by a draft or proposed term keeps the draft sta const emitted = JSON.parse(fs.readFileSync(path.join(ROOT, 'docs/api/v1/of/records/utah-mental-health-chatbot-disclosure-2026q2-first-session-disclose-genai-on-first-session.json'), 'utf8')); assert.deepEqual([emitted.lifecycle_status, emitted.operative_status, emitted.enforcement_status], ['draft', 'future', 'unsignaled']); }); + +test('a PubLedge original draft cites itself as source and its own section as locator', () => { + const config = { url: 'https://publedge.org/' }; + const evidence = path => ({ kind: 'instrument', native_path: path, native_file_sha256: '1'.repeat(64), canonical_unit: null, canonical_sha256: '2'.repeat(64), admission_status: 'legacy-unreviewed', review_packet_sha256: null, retained_primary_sha256: null, unresolved_review_state: 'unknown', unresolved: null }); + const primary = { id: 'example-duty', name: 'Example duty', group: 'requirement', _body: '## Summary\n\nExample.\n', _evidence_input: { ...evidence('data/examples/obligations/example-duty.md'), kind: 'obligation-definition' } }; + const project = container => { + const mapping = { id: 'example-mapping', regulation: container.id, obligations: ['example-duty'], source_heading: 'Example Section (§1-2-3)', _evidence_input: { ...evidence('data/examples/mapping/index.yml'), kind: 'mapping-entry' } }; + const records = obligationFirst.buildObligationFirstRecords(config, { containers: [container], primaries: [primary], authorities: [], mappingIndex: [mapping] }); + return { instrument: records.instruments[0], term: records.terms[0], duty: records.obligations[0] }; + }; + const base = { id: 'us-ut-oaip-jia-2099-001', type: 'jia', status: 'proposed', jurisdiction: 'us-ut', authority: 'utah-oaip', official_url: 'https://authority.example/ai/', _canonicalPath: 'us/utah/oaip/jia/2099-001/', parties: [{ name: 'Utah OAIP', role: 'interpreting_authority' }], _evidence_input: evidence(JIA_FILE) }; + + const draft = project({ ...base, source: 'publedge-original-draft' }); + for (const record of [draft.instrument, draft.term, draft.duty]) assert.equal(record.source, 'https://publedge.org/us/utah/oaip/jia/2099-001/'); + for (const record of [draft.term, draft.duty]) assert.equal(record.source_locator, 'Example Section (§1-2-3)'); + + // Negative control: an authority-published record keeps the authority's source. + const remap = project({ ...base, source: 'demonstration-remap', status: 'enforcing' }); + for (const record of [remap.instrument, remap.term, remap.duty]) assert.equal(record.source, 'https://authority.example/ai/'); + + const emitted = JSON.parse(fs.readFileSync(path.join(ROOT, 'docs/api/v1/of/records/utah-mental-health-chatbot-disclosure-2026q2-first-session.json'), 'utf8')); + assert.equal(emitted.source, 'https://publedge.org/us/utah/oaip/jia/2026-001/'); + assert.equal(emitted.source_locator, 'First-Session Disclosure (§13-72a-203)'); + assert.deepEqual(emitted.anchors, ['https://everyailaw.com/term/utah-sb149-chatbot-disclosure.json'], 'the interpreted statute stays linked through the anchor'); +});