Skip to content

DiscussionBridge for Astro Machine Manual

Historical Astro implementation reference. Do not use this page as a current package-family install contract. Use the Alpha Installation and Operator Guide, then the exact README and immutable artifact for the selected platform profile.

This is the exact, reusable implementation memory for DiscussionBridge for Astro. Use it with the Human Manual to generate a site-specific runbook. It may name variables, paths, endpoints, and scopes; it must never contain real secret values.

product: DiscussionBridge
architecture: Discourse-centered_adapter-driven
operational_home: DiscussionBridge for Discourse
control_plane_host: Discourse
portable_core:
owns:
- connections
- identities
- mappings
- policies
- jobs
- comparisons
- approvals
- retries
- provenance
- audit_evidence
adapters:
current: [Astro]
planned: [Statamic, future_publishing_systems]
rule: adapters_translate_portable_contract_and_do_not_create_control_planes
tier_1_API_only:
status: supported_compatibility_capability
natural_operational_center: false
portability:
rule: keep_core_domain_logic_host-neutral_where_practical
future_host_option: standalone_without_domain_rewrite
implementation_status:
architecture_decision: settled
core_plugin_adapter_migration: open
product_family:
umbrella: Discussion_Bridge
free_products:
- Discussion_Bridge_for_Discourse
- Discussion_Bridge_for_Astro
paid_managed_product:
name: Discussion_Bridge_SaaS
purpose: multi_CMS_multi_site_multi_community_orchestration
paid_services:
- implementation
- migration
- customization
- training
- operations
- extensive_support
community:
public_docs: true
community_support: true
team_help: as_capacity_permits
commercial_rule: SaaS_sells_managed_operation_scale_governance_convenience_and_operational_relief_not_artificial_limit_removal
shared_foundation: portable_Discussion_Bridge_Core_contracts_policies_terminology_identity_and_trust_model
Astro_product: DiscussionBridge for Astro
Astro_package: astro-discussion-bridge
package_root: packages/astro-discussion-bridge
cli_source: packages/astro-discussion-bridge/src/cli.ts
sync_source: packages/astro-discussion-bridge/src/sync/index.ts
import_source: packages/astro-discussion-bridge/src/import-existing.ts
public_docs: docs
default_starlight_dir: src/content/docs
default_astro_dir: src/content

Classify new and existing behavior before moving or extending it:

behavior_classification:
portable_core:
test: owns_domain_policy_state_or_audit_evidence
Discourse_host:
test: uses_Discourse_users_permissions_jobs_UI_database_APIs_or_operations
publishing_adapter:
test: maps_portable_contract_to_CMS_content_navigation_rendering_build_or_deploy
prohibited:
- duplicate_control_plane_per_adapter
- unnecessary_Discourse_internal_dependency_in_portable_domain_logic
- claim_migration_complete_before_reviewed_implementation_evidence

Package commands run from the consuming Astro project root:

Terminal window
npx astro-discussion-bridge --help
npx astro-discussion-bridge check-discourse [options]
npx astro-discussion-bridge publish-new [docsDir] [options]
npx astro-discussion-bridge sync-existing [docsDir] [options]
npx astro-discussion-bridge publish-and-sync [docsDir] [options]
npx astro-discussion-bridge import-existing [docsDir] --topic URL[,URL] [options]

sync is a backward-compatible alias for publish-new; do not use it in new runbooks because the side effect is less obvious.

Collect and validate before generating a runbook:

site_name: required
repository: required
project_root: required
environment: dev | staging | live | placeholder
framework_preset: astro | starlight
site_url: required absolute HTTPS URL for live use
discourse_url: required absolute URL
post_as: preferred request actor for live writes
legacy_api_username: optional compatibility fallback
publishing_key_location: private reference only; never key value
diagnostics_key_location: private reference only; never key value
active_target: optional logical target name
comments_display: simple | full | fullInteractive
deployment_target: optional, e.g. Cloudflare Pages
verification_urls: required for live lanes
lanes:
- name: required
docs_dir: required
route_base: optional
source_mode: astro-managed | discourse-managed | discourse-imported
category_id: required for create/update intent
tags: []
listed: true | false
managing_page_rule: exactly one managing Astro page per topic
recovery_owner: required for production

Reject or pause generation when source mode, route base, public URL, destination forum, category, or managing page is unknown.

Use for publish-new, sync-existing, and publish-and-sync.

Exact settled granular scopes:

categories:list
categories:show
posts:edit
posts:list
search:show
tags:list
topics:write
topics:update
topics:read
topics:status

Known allowed-parameter entries from the Discourse granular-key UI:

categories show: id=any
posts edit: id=any
search show: q=any, page=any
topics write: topic_id=any
topics update: topic_id=any, category_id=any
topics read: topic_id=any, external_id=any
topics status: topic_id=any, category_id=any, status=any, enabled=any

The API user also needs the forum/category authority required by the action. Retitling replied topics and changing listing status may require staff or moderator capability even when the key has the matching endpoint scope.

Current fallback: global/admin-capable, read-oriented setup/source key. Use for check-discourse and controlled import-existing source reads when the granular key cannot read the required raw post. Do not use this key for publishing, reconciliation, CI/build, or routine runtime/deploy paths.

Target future state: a granular diagnostics/read key after required Discourse site metadata scopes are confirmed.

Every key-creation interaction MUST present the applicable block with the key description, user, scope, and permissions. The operator MUST copy the block into the respective protected credential file above the secret value. Never request, echo, log, or write the real key outside the protected credential store.

Publishing key:

Purpose: Runtime publishing granular key
Use: publish-new, sync-existing, publish-and-sync, check-discourse basic limits
Bot user role: Admin currently; intended future runtime posture is non-admin or least-privilege
Key scope: Granular
Operational rule: Use this to validate the minimum permissions needed for normal bridge publishing.

Diagnostics key:

Purpose: Diagnostics/setup and protected source-read key
Use: check-discourse; controlled import-existing source reads when granular raw-post access fails
Bot user role: Admin
Key scope: Global or admin-read capable
Operational rule: Do not use in CI/build unless explicitly intended

The complete credential-file templates, including the settled publishing scopes and secret placeholder, are in docs/KEY_MANAGEMENT.md.

DISCOURSE_URL
SITE_URL
DISCOURSE_POST_AS
DISCOURSE_API_USERNAME
DISCOURSE_API_KEY
DISCOURSE_DIAGNOSTICS_API_KEY
DISCOURSE_CATEGORY_ID
DISCOURSE_TAGS
DISCUSSION_TARGET
DISCUSSION_PAGE_URL
DISCOURSE_NOTIFY_RECIPIENTS
DISCOURSE_TITLE_MIN_LENGTH
DISCOURSE_MAX_TOPIC_TITLE_LENGTH
DISCOURSE_MAX_POST_LENGTH
DISCOURSE_MAX_TAGS_PER_TOPIC
DISCOURSE_MAX_TAG_LENGTH

Resolution behavior:

  • CLI values override environment values.
  • check-discourse prefers --diagnostics-api-key or DISCOURSE_DIAGNOSTICS_API_KEY, then falls back to the publishing key.
  • --dry-run publish/sync does not require API username/key.
  • live publish/sync/import requires DISCOURSE_API_USERNAME and DISCOURSE_API_KEY.
request_actor:
preferred_inputs:
environment: DISCOURSE_POST_AS
cli: --post-as
publishOnBuild_lane_or_default: [postAs, postAsEnv]
legacy_fallbacks:
environment: DISCOURSE_API_USERNAME
cli: --api-username
publishOnBuild_lane_or_default: [apiUsername, apiUsernameEnv]
precedence:
- explicit_or_lane_postAs
- named_postAsEnv
- DISCOURSE_POST_AS
- legacy_apiUsername_controls
request_header: Api-Username
live_output: "Post as: USER"
diagnostics_output: "Request actor"
changes_existing_topic_owner: false
api_key_authority:
user_level:
All_Users: may_act_for_supplied_Api_Username
Single_User: bound_to_selected_user
scope:
values: [Global, Read-only, Granular]
purpose: endpoint_and_action_authority
invariant: user_level_and_scope_are_independent
service_identity:
collision_rule: no_actual_or_visually_ambiguous_nonhuman_identity_across_forums
naming_rule: role_plus_origin_system
candidates:
- { username: editorbridgeforum, public_name: DiscussionBridge Forum Editor }
- { username: editorcanforum, public_name: CAN Forum Editor }
verify_before_create: [normalized_username, site_length_limits, availability]
preserved_source_identity: obbba-bot
inventory_group:
name: special-admin
grants_admin_status: false
grants_API_rights: false
grants_category_permissions: false
discourse_mermaid:
official_existing_option:
type: theme_component
meta: https://meta.discourse.org/t/discourse-mermaid/218242
repository: https://github.com/discourse/discourse-mermaid-theme-component
distinct_paths:
- existing_official_theme_component
- fork_or_extension_of_theme_component
- separate_Discussion_Bridge_for_Discourse_plugin
- upstream_Discourse_change
forbidden_term: Discussion_Bridge_Mermaid_plugin
tier_1_API_only_dependency: none
Source mode Required operational guard Writable by publish/sync?
astro-managed explicit ownership decision yes
discourse-managed discussionSync: false no
discourse-imported discussionSync: false until explicit promotion no

Current implementation facts:

  • discussionSync: false is read and enforced by sync preflight.
  • A guarded page reports skipped with reason discussionSync is false.
  • Frontmatter parse/update paths accept LF and CRLF boundaries and preserve the source file’s existing line-ending style when writing updates.
  • Sync preflight remains guard-driven, while the reviewed import path generates discussionSourceMode: discourse-imported and boolean discussionSync: false.
  • Import preserves the Discourse topic ID and URL.

Therefore, the required Alpha import procedure is:

  1. run import-existing --dry-run;
  2. run the live import only after reviewing the destination;
  3. verify the generated source mode, boolean sync guard, topic ID, and URL;
  4. review frontmatter before any directory-wide sync;
  5. preserve and commit the imported source before promotion;
  6. promote only by changing discussionSourceMode to astro-managed, setting discussionSync: true, and selecting the explicit writable target when target bindings are present;
  7. run sync-existing --dry-run --details before the first promoted write.

Line-ending invariant:

accepted_frontmatter_boundaries:
- LF
- CRLF
update_behavior: preserve existing source line-ending style
required_regression_case: discussionSync false is enforced for CRLF frontmatter
required_write_regression: frontmatter updates preserve CRLF source style

Publishing may write:

discussionTarget: "community" # only when a target is active
discourseTopicId: 123
discourseTopicUrl: "https://forum.example.com/t/example/123"
discussionSourceHash: "sha256-value"
discussionLastSyncedAt: "ISO-8601 timestamp"

Import currently writes:

discussionTarget: "community" # optional
discourseTopicId: 123
discourseTopicUrl: "https://forum.example.com/t/example/123"
discussionSourceHash: "sha256-value"
discussionImportedAt: "ISO-8601 timestamp"
discussionCommentsDisplay: "full" # only when requested

Operator-supplied controls and overrides include:

discussionSync: false
discussionCommentsDisplay: simple # simple | full | fullInteractive
discussionSummary: |
Curated Discourse-safe companion content.
discourseCategoryId: 5
discussionTags: "product, docs"

Reconciliation contract:

explicit_existing_topic:
input: discourseTopicId
embed_config: '{ topicId }'
page_url_reconciliation_required: false
verification: read and validate the explicit topic directly
url_owned_topic:
input: no discourseTopicId
embed_config: '{ discourseEmbedUrl: embedUrl }'
page_url_reconciliation_required: true

Keep embed-info/exact-URL-search results in diagnostics even for explicitly linked topics, but do not treat a 404 or no URL owner as a topic failure when the explicit topic is healthy.

Read-only endpoints may include:

/site/settings.json
/site.json
/categories.json
/tags.json
/embed/info?embed_url=...
exact URL search fallback

Canonical command:

Terminal window
npx astro-discussion-bridge check-discourse \
--discourse-url https://forum.example.com \
--category-id 5 \
--tags product,docs \
--page-url https://docs.example.com/example-page/

Global diagnostics-key example:

Terminal window
DISCOURSE_DIAGNOSTICS_API_KEY=diagnostics-key \
npx astro-discussion-bridge check-discourse \
--discourse-url https://forum.example.com \
--api-username discussionbridge-editor \
--category-id 5 \
--tags product,docs \
--page-url https://docs.example.com/example-page/

Granular publishing-key example with reviewed explicit limits:

Terminal window
DISCOURSE_API_KEY=granular-publishing-key \
npx astro-discussion-bridge check-discourse \
--discourse-url https://forum.example.com \
--api-username discussionbridge-editor \
--category-id 5 \
--tags product,docs \
--min-topic-title-length 15 \
--max-topic-title-length 255 \
--max-post-length 32000 \
--max-tags-per-topic 6 \
--max-tag-length 30

The granular run may still report settings/capabilities/reconciliation as 403 warnings. Explicit limits constrain local validation; they do not manufacture missing read authority.

Expected output sections:

Discourse URL
Site settings
Site capabilities
Limits
Tag capabilities
Category
Requested tags / Tag inventory / Tag issues
Setup issues / Setup warnings
Reconciliation lookup (when page URL supplied)

Exit code is nonzero when tag issues or setup issues exist. Unavailable metadata may be reported as warnings/unknown values.

Creates only missing companion topics and skips linked pages.

Terminal window
npx astro-discussion-bridge publish-new src/content/docs --dry-run --details
npx astro-discussion-bridge publish-new src/content/docs

Expected per-page statuses include dry-run-create, created, skipped, and failure output. A live create writes topic link and sync metadata to frontmatter.

Updates only pages with discourseTopicId; skips missing links and guarded pages.

Terminal window
npx astro-discussion-bridge sync-existing src/content/blog \
--route-base blog --dry-run --details
npx astro-discussion-bridge sync-existing src/content/blog --route-base blog

Expected statuses include dry-run-update, updated, unchanged, and skipped. --force rewrites the managed first post even when the source hash is unchanged. --unlist changes topic visibility and may require staff authority.

Creates missing topics and syncs linked topics in one explicit run:

Terminal window
npx astro-discussion-bridge publish-and-sync src/content/releases \
--route-base releases --dry-run --details

Use only after checking that every non-Astro-managed page in the directory has discussionSync: false.

Terminal window
npx astro-discussion-bridge import-existing src/content/docs \
--topic https://forum.example.com/t/example/123 \
--source-mode discourse-managed \
--site-url https://docs.example.com \
--comments-display full \
--dry-run

Hero options:

--hero-image PATH|URL
--hero-alt TEXT

Validation contract:

pairing: bidirectional_required
hero_alt: non_empty_after_trim
explicit_errors:
- bare option
- inline-empty value
- whitespace-only alt
- hero image without alt
- hero alt without image
output:
placement: leading image before raw body
image_syntax: angle-wrapped destination
alt_escaping: supported
internal_path_spaces: supported

Prune option:

--prune-profile community-call-to-action
profile: community-call-to-action
mode: opt_in
removal_scope: trailing block after horizontal rule
markers_all_required:
- Join the Conversation Today
- /signup
- Please share how
- /c/stories/
failure_before_io:
- no verified boundary
- unknown profile
- duplicate profile
- bare option
- empty value
success_metadata:
discussionImportPolicy: pruned:community-call-to-action

Accepted topic references: numeric ID or URL whose host matches DISCOURSE_URL. Expected statuses: dry-run-import, dry-run-overwrite, imported, skipped. Existing files are skipped unless --overwrite is used. --source-mode accepts discourse-imported or discourse-managed, defaults to imported, and rejects astro-managed. Generated frontmatter always includes the selected discussionSourceMode and discussionSync: false. Manifest entries use sourceMode; the same validation is applied before write.

selection_modes:
curated:
input: explicit topics or manifest
ordering: preserve caller-supplied order
next_in_category:
command: discover-imports
operation: read_only_preview
category_discovery: list available categories and subcategories
category_selector: ID or unambiguous slug/name
category_selection: required before queue preview
include_descendants: optional
default_order: created_at ascending
tie_breaker: topic ID ascending
filters_optional:
- tags
- created_at range
- open/closed status
- limit
ordering_optional:
- oldest by created_at
- newest by created_at
- natural topic title/name for numbered collections
forbidden_order_fields:
- bumped_at
- last reply
- latest activity
pre_import:
validate_before:
- network_fetch
- local_scan
- dereference
- filesystem_work
invalid_runtime_values:
fields: [sourceMode, commentsDisplay]
result: reject_with_zero_fetch
preview_selected_category_queue: required
preview_candidates: required
exclude_already_imported_topics:
source_fields:
- opening_frontmatter.discourseTopicId
- strictly_parsed_opening_frontmatter.discussionTargetBindings.topicId
unrelated_topicId_metadata: eligible
descendant_categories:
fetch: direct
duplicate_topics: deduplicated
date_only_created_to: include_full_UTC_day
manifest_output:
option: --manifest-out FILE
format: strict_v1
overwrite: refused
default_sourceMode: discourse-imported
selectable_sourceMode: [discourse-imported, discourse-managed]
selectable_commentsDisplay: [simple, full, fullInteractive]
other_output:
JSON: --json
public_category_requirements:
site_URL: not_required
credentials: not_required
review_status:
implementation: complete
package_suite: 84/84
live_read_only_CDN_proof:
forum: https://forum.repealobbba.org
category: 18
tags: [TITLE-I]
order: natural-title
limit: 10
scanned: 320
excluded_already_imported: 5
candidates: [754, 755, 756, 757, 758, 759, 761, 762, 763, 764]
files_written: 0
Code_Boss: PASS_after_three_correction_rounds
full_attribution_and_package_gate: PASS
site_specific_dry_run_example:
site: onebigbeautifulbill.us
manifest: discussionbridge-imports-title-i-10106-10306.json
topics: [754, 755, 756, 757, 758, 759, 761, 762, 763, 764]
target: repeal-obbba
route_base: title-i
result: { imported: 0, skipped: 0, dry_run: 10, generatedPages: 0 }
writes: { Discourse: 0, Astro_content: 0 }
completed_followup:
granular_attempt:
topic_endpoint: { path: /t/754.json, HTTP: 200, first_post_raw: absent }
raw_post_fallback: { path: /posts/761.json, resource: first_post_of_topic_754, identifier_kind: post_id, HTTP: 403 }
result: stopped_pre_write_invalid_access
operational_rule: use_protected_diagnostics_global_key_for_controlled_import_source_reads_when_granular_raw_post_access_fails
live_import: { imported: 10, skipped: 0, dry_run: 0, Discourse_writes: 0 }
content_commit: 5cfc99a
cleanup_commit: a5f5df9
clean_build_HTML: 17
corrected_worker_version: 2fa24e22-2f79-4053-9f3b-436cf9f776b4
live_routes: { expected: 10, HTTP_200: 10 }
stock_routes: { expected_404: 3, verified_404: 3 }
proven_gate: live_import_build_deploy_and_per_route_verification
alpha_requirement: true

The stable comparison key for the default queue is (created_at, topic_id). Community replies must never reorder publishing candidates.

Manifest refresh gate:

command: import-existing --manifest PATH --overwrite
purpose: deterministic multi-page refresh with per-topic policy
schema:
format: strict_json
top_level_keys: [version, imports]
manifest_entry_fields:
- topic
- requiredTags
- output
- commentsDisplay
- heroImage
- heroAlt
- pruneProfiles
ordering: preserve caller-supplied manifest order
reject:
- duplicate_topics
- manifest_and_direct_option_mixing
validation:
- runner_revalidation
- dry_run_collision_and_path_preflight
- path_containment_before_writes
write_model:
- stage_all_entries_before_writes
- exclusive_atomic_creation_without_overwrite
- atomic_overwrite_with_rollback
regression_coverage:
- slug_drift
- destination_race
- zero_byte_output
- path_traversal
blanket_update_all_safe: false
package_gate: pass_51_of_51
obbba_site_live_proof: pass_topics_434_747_751_752_753

Every import route has two validated contracts:

WHEREFROM:
discourse_base_or_target: required
topic_identity_or_curated_manifest_order: required
category: required_when_lane_uses_one
required_tags_and_filters: validate_against_live_source_before_write
WHERETO:
docs_dir: deterministic Astro content root
output: safe relative .md or .mdx file
public_identity: site_url + route_base
navigation: Astro navigation lane
invariants: [deterministic, reviewable, path_contained, never_latest_activity]
manifest_v1_mapping:
wherefrom: [topic, requiredTags]
whereto: [docsDir, output, site-url, route-base, astro_navigation_lane_map]
future_schema_note: nested from/to may be considered later; do not redesign v1 now

requiredTags comparisons are case-insensitive assertions against live Discourse tags and fail before any write. Discourse topic tags may arrive as strings or objects. output must be a safe relative .md or .mdx path; nested parent directories are created only after the entire destination passes validation and containment checks.

Stock Starlight docsSchema() may strip custom bridge fields, and imported Markdown pages do not contain a hand-written <Discussion> component. A Starlight consumer must:

  1. extend docsSchema with the DiscussionBridge frontmatter fields;
  2. install src/components/MarkdownContent.astro at the page boundary;
  3. wire it through starlight.components.MarkdownContent;
  4. remove per-page explicit <Discussion> instances when the boundary override is active, preventing duplicate discussions.

Verification requires exactly one discussion instance per linked page with the expected topic ID and display mode.

--dry-run
--details
--target NAME
--route-base PATH
--discourse-url URL
--site-url URL
--api-username USER
--api-key KEY
--tags TAG[,TAG]
--category-id ID
--force
--unlist
--notify-on-failure
--notify-recipients USER[,USER]
--title-min-length N
--max-topic-title-length N
--max-post-length N
--max-tags-per-topic N
--max-tag-length N
--skip-title-validation

Do not put real keys on a command line in a runbook; use protected environment variables so keys do not enter shell history.

URL derivation joins siteUrl, normalized routeBase, and the Markdown path relative to docsDir, with index collapsed to its parent path.

Examples:

docsDir=src/content/blog
file=src/content/blog/content-lanes.md
routeBase=blog
result=https://docs.example.com/blog/content-lanes/
docsDir=src/content/releases
file=src/content/releases/2_1.md
routeBase=releases
result=https://docs.example.com/releases/2_1/

Pre-write invariants:

  • one managing Astro source page per Discourse topic in a run;
  • no duplicate managed page URL in a run;
  • active discussionTarget must match --target/DISCUSSION_TARGET;
  • display-only comparison pages use discussionSync: false;
  • category and tags are checked before live writes;
  • computed URLs are reviewed with --details.
discussionBridge({
provider: "discourse",
discourseUrl: "https://forum.example.com",
siteUrl: "https://docs.example.com",
comments: {
display: "full", // simple | full | fullInteractive
embedHeight: "800px",
dynamicHeight: true,
embedMinHeight: "360",
embedMaxHeight: "900",
className: "discussion-bridge-embed",
},
replies: {
refreshOnPageLoad: true,
refreshEndpoint: "/api/discourse/topics/{topicId}.json",
renderMermaid: true,
},
});
  • simple: Discourse embeddable-comments script; limited display control and metadata.
  • full: Astro-rendered replies; interaction remains in Discourse; browser refresh needs CORS or same-origin proxy.
  • fullInteractive: Discourse full-app iframe; requires full-app embedding and compatible sign-in/cookie configuration.

Rendering boundary:

fullInteractive:
owner: cross_origin_Discourse_iframe
dynamic_height:
default: true
initial: 800px
min_px: 360
max_px: 900
responsive_max: prohibited_competing_CSS_ceiling
legacy_embedViewportMaxHeight: none_only_or_configuration_failure
operator_disable: dynamicHeight_false
purpose: let_qualified_Discourse_Core_own_dynamic_iframe_height_without_host_clipping
host_Astro_transforms_or_CSS_cross_boundary: false
mermaid_and_table_styling_owner: Discourse
ordinary_topic_434_mermaid_theme_result: SVG
full_app_embed_topic_434_mermaid_result: raw_code
full_app_embed_theme_component_js_loaded: false
table_parse: pass
table_presentation: weak_until_embedded_CSS
immediate_table_path: Discourse common/embedded.scss targeted by embed class
mermaid_embed_solution: open_extension_plugin_or_upstream
full:
owner: Astro_rendered_bridge_component
parity_review: pass_d7800d7_code_boss_final
renderMermaid_default: true
renderMermaid_opt_out: false
mermaid_version: 11
security_level: strict
loading: lazy_when_reply_contains_mermaid
failure: preserve_source_and_allow_module_load_retry
tables: readable_borders_padding_and_horizontal_overflow
repeated_components: claim_each_replies_container_once
embed_class_hooks:
comments.className: forwarded_to_window.DiscourseEmbed.className
embedClassName_components: [Discussion, DiscourseDiscussion, DiscourseComments]

The lazy Mermaid chunk is emitted during a full-capable build and may trigger Vite’s greater-than-500-kB warning, but browsers fetch it only when a full-mode reply contains Mermaid.

Verification matrix:

simple: embed loads, full discussion link works
full: build/render fetch works, browser refresh works, unavailable state works
fullInteractive: logged-out load, logged-in reply/like/quote, mobile height/CSP

For a live signed-in interaction item, record sanitized evidence:

topic_id: expected topic
post_number: created test post number
direct_post_url: public verification URL
content_marker: non-sensitive test text
post_count_after: observed count
astro_embed_signature_after:
topic_id: expected topic
full_app: true
retired_renderer: absent
private_account_identifier: omit

Creating the reply is an intentional browser-session action, not a package publish/sync/import operation. Verify the forum result read-only afterward.

Fresh-import gate matrix:

cases:
- { hero: false, prune: false }
- { hero: true, prune: false, alt_text: required }
- { hero: false, prune: true }
- { hero: true, prune: true, alt_text: required }
per_case_assertions:
- discussionSourceMode == discourse-imported
- discussionSync == false
- topic ID and URL preserved
- build/deploy/live render pass
- comments pass
- no writeback

Do not use an existing-page migration or signed-in interaction result as a substitute for this matrix.

Component propagation invariant:

Discussion.astro -> DiscourseDiscussion.astro -> DiscourseComments.astro

If topicId is supplied, every layer must preserve it and the browser embed configuration must use { topicId }. Regression tests must cover this path.

Shipped browser declaration contract:

type DiscourseEmbedConfig =
| { topicId: number; discourseEmbedUrl?: never }
| { discourseEmbedUrl: string; topicId?: never };
// Both alternatives may also include:
// fullApp?: boolean
// embedHeight?: string

Do not model topicId and discourseEmbedUrl as simultaneously required or freely co-present; they represent alternative ownership/linking paths.

Current comments-boundary credit behavior and configuration:

comments_credit:
enabled_by_default: true
operator_disable_supported: true
prefix: Connected by
label: DiscussionBridge
href: https://discussionbridge.dev/
href_protocols: [http, https]
escaped_plain_text: [prefix, label]
independent_of_discourse_powered_by: true
placement: centered_after_complete_discussion_surface
full_interactive_placement: outside_cross_origin_iframe
visually_secondary: true
accessible: true
reduced_motion: true
supported_modes: [simple, full, fullInteractive]
hard_coded_in_site_content: false
stable_classes:
- discussion-bridge-credit
- discussion-bridge-credit__prefix
- discussion-bridge-credit__brand
stable_data_hooks:
- data-discussion-bridge-credit

10. Cloudflare Pages / Domain Verification

Section titled “10. Cloudflare Pages / Domain Verification”

CDN-backed Discourse compatibility evidence

Section titled “CDN-backed Discourse compatibility evidence”
verified_at: 2026-07-22
forum: https://forum.repealobbba.org
forum_edge: Cloudflare_CDN
status: PASS_for_exercised_production_workflows
tested:
- check_discourse_and_API_reads
- Discourse_topic_imports_to_Astro
- target_topic_reconciliation
- protected_source_topic_links
- fullInteractive_comments
- signed_in_reply_behavior
- five_live_source_disclosures
- source_and_cross_target_no_writeback
- canonical_Astro_production_pages
claim_limit: no_guarantee_for_every_CDN_WAF_cache_configuration
preserve_through_CDN:
- Discourse_API_paths
- JSON_endpoints
- embed_and_full_app_routes
- authentication_and_cookies
- websocket_behavior
diagnostic_rule: compare_edge_and_direct_origin_then_investigate_cache_WAF

Do not record private Cloudflare account labels, rule identifiers, or access values. If edge and origin results differ, capture sanitized path/status/cache evidence and route the CDN/WAF configuration issue to Ops.

Cloudflare-specific values are site inputs, not package constants. Record:

repository: canonical repository URL
production_branch: main
root_directory: consuming Astro project path
build_command: npm run build
output_directory: site-specific Astro output, commonly dist
custom_domain: exact public hostname
astro_site: exact public URL
discussion_bridge_site_url: exact public URL
discourse_embed_host: exact hostname
account_id: explicit deployment account identifier in approved site config
worker_name: exact Worker name when using Workers
worker_version: deployment evidence
workers_dev_endpoint: deployment verification endpoint

When more than one Cloudflare account is available, pin the intended account_id in the approved deployment configuration so CLI/CI selection is deterministic. Manuals and support bundles should describe the placement without copying private account labels or login email addresses.

Verification:

  1. Pages deployment corresponds to the intended commit and canonical source.
  2. Custom domain resolves and HTTPS is valid.
  3. Astro site, DiscussionBridge siteUrl, CLI SITE_URL, and the public hostname agree.
  4. Discourse allows that exact embed hostname.
  5. A lane page and its companion topic resolve in both directions.
  6. The selected comments mode works on desktop and mobile.
  7. Cache bypass or narrowly scoped purge is tested before declaring stale output a failed sync/deploy.
  8. The Worker endpoint and canonical domain serve the intended candidate.
  9. Generated HTML contains the expected package/topic signature and does not contain the retired renderer signature.

Before deployment commits, inspect the consuming site’s worktree. Preserve and report unrelated pre-existing changes; do not absorb them into deployment-only commits.

Build the exact tracked candidate from a clean checkout or detached worktree before release. A dirty local deletion can hide a stale tracked page or asset reference and make the working-tree build pass when the committed candidate fails. Isolate the correction in its own reviewed commit, rebuild that exact commit, and leave unrelated unstaged changes and untracked artifacts untouched.

Failure Detection Recovery
Missing credentials CLI missing-configuration message Set protected env vars; rerun dry run.
Site metadata 403 check-discourse unavailable/warning Use diagnostics key or explicit preflight limits.
Title/body/tag validation Local preflight failure Correct content/settings; rerun dry run.
Embed URL already taken Publish error or reconciliation output Prove ownership, resolve with diagnostics, then link/retry.
Page URL has no embed owner but topicId is explicit Embed-info 404 or exact search has no result Validate the explicit topic and generated { topicId }; do not auto-relink.
Wrong category/route --details or post-write verification Stop writes; correct lane; assess/relink affected topic explicitly.
Active target mismatch skipped with target reason Use the matching --target; do not remove labels casually.
discussionSync is false guarded page skipped Expected for display/import/Discourse-owned pages; remove only on approved promotion.
Topic deleted topic read failure Prefer Discourse restore; otherwise verify and commit an explicit relink/replacement. Never auto-recreate or match by similar title.
First post deleted missing-first-post failure Restore with Discourse controls; if identity cannot remain, use the same reviewed topic-replacement procedure.
Discourse offline clear network/API failure Preserve Astro shell; retry after service recovery.
Stale CDN output source/topic correct but public view stale Verify commit/topic, bypass cache, then purge relevant cache only.

CLI/build output is authoritative. Failure-notification PMs are best effort and must not be treated as the only failure record.

Recovery sequence invariant:

recovery:
preserve_source_first: true
record_old_binding: [topic_id, topic_url, target_name]
diagnose: [check_discourse_page_url, sync_existing_dry_run_details]
preferred_action: restore_existing_discourse_identity
replacement_requires:
- explicit_operator_decision
- verified_topic_ownership_category_permissions
- atomic_topic_id_and_url_source_change
- selected_target_binding_update_when_present
recreate_requires:
- committed_removal_of_stale_binding
- prior_binding_retained_in_git_history
- publish_new_dry_run_details
- stale_plugin_mapping_disposition_when_applicable
forbidden: [automatic_guess, title_similarity_match, retry_successful_targets]
1. Confirm intended package build/version.
2. Confirm lane inputs and source modes.
3. Run check-discourse.
4. Run intended operation with --dry-run --details.
5. Review every page URL, target, topic ID, category, tag, and reason.
6. Run live command without changing other arguments.
7. Verify Discourse topic, first post, metadata, tags, and listing state.
8. Verify Astro source/frontmatter and local build.
9. Verify deployed URL, comments mode, and cache state.
10. Sanitize logs before sharing; update manuals with newly confirmed facts.

13. Multi-Target Frontmatter And Execution

Section titled “13. Multi-Target Frontmatter And Execution”

The frontmatter values are YAML scalars. CSV fields preserve target order; the binding map is serialized JSON:

discussionSourceMode: discourse-imported
discussionSync: false
discussionTarget: repeal-obbba
discussionSourceTarget: repeal-obbba
discussionTargets: repeal-obbba,citizen-activist
discussionPublishTargets: citizen-activist
discussionPrimaryTarget: repeal-obbba
discussionTargetBindings: '{"repeal-obbba":{"topicId":434,"topicUrl":"https://forum.repealobbba.org/t/434","status":"synced"},"citizen-activist":{"status":"failed","lastError":"sanitized target error","lastAttemptedAt":"2026-07-22T00:00:00.000Z"}}'

Operate one target per CLI invocation:

Terminal window
npx astro-discussion-bridge publish-and-sync src/content/docs --target citizen-activist --dry-run
npx astro-discussion-bridge publish-and-sync src/content/docs --target citizen-activist

discussionSync: false does not authorize source writeback. The named source remains protected for discourse-imported and discourse-managed; only a target listed in discussionPublishTargets is writable. New targeted imports set both legacy discussionTarget and discussionSourceTarget. A legacy imported page without the latter protects its legacy discussionTarget.

Run ordered publishOnBuild.lanes sequentially when build-time publishing is intended. Each lane needs targetName and may override discourseUrl, apiKey/apiUsername, or named apiKeyEnv/apiUsernameEnv. Do not put secret values in frontmatter, manuals, or committed configuration.

On failure, inspect only the active target’s binding. Preserve other successful bindings and retry with the failed --target. A stored error is whitespace- normalized, truncated, and paired with lastAttemptedAt. A reconciled 422 embed/title collision records the discovered owning topic in the active binding and clears its failure state. Invalid binding JSON or shape must fail before network access.

implementation:
commit: a9d2097
review: Code_Boss_PASS
tests: 68_of_68_PASS
package_dry_run_exports:
- dist/source.*
- DiscussionSource.astro
- package_root_helpers_and_types
- astro-discussion-bridge/source
public_api:
component: astro-discussion-bridge/DiscussionSource.astro
helper: resolveDiscussionSourceNotice
types: [DiscussionSourceMode, DiscussionSourceNotice]
rendering:
placement: near_article_start
separate_from: [comments_boundary, Discussion_Bridge_credit]
aria_label: Content source
prefix: "Source:"
default_source_label: Discourse
modes:
discourse-imported: This page originated in {sourceLabel} and was imported here for publication.
discourse-managed: This page is managed in {sourceLabel} and published here for easier reading.
astro-managed: no_notice
unknown: no_notice
source_url_precedence:
- explicit_sourceUrl_prop
- discussionImportedFrom
- protected_discussionSourceTarget_binding
- legacy_discussionTarget_binding_fallback
- legacy_discourseTopicUrl
accepted_link_protocols: [http, https]
unsafe_or_malformed_candidates: skip
no_safe_url: render_notice_without_link
multi_target_rule: provenance_follows_protected_source_not_publication_target
custom_props: [sourceLabel, message, linkLabel, class, mode, sourceUrl, targetBindings, frontmatter]
site_wiring:
plain_Astro: canonical_BlogPost_layout
Starlight: MarkdownContent_override
OBBBA:
adoption_status: complete
adoption_commit: aa7846d
artifact: vendor/astro-discussion-bridge-0.1.0-alpha-a9d2097-f3fbb73e.tgz
artifact_sha256: F3FBB73E95D52B5799FBEBE5221298040FD32292EDA8BD76C257C0C19E4267B2
Code_Boss_adoption_review: PASS
clean_detached_npm_ci_build: PASS
publishOnBuild: false
Discourse_writes: none
worker_version: 005b9ff2-c880-43e4-b759-31ec2d02bed5
live_routes_verified: 5
per_route:
Content_source_asides: 1
source_links: 1
source_forum: forum.repealobbba.org
source_label: Repeal OBBBA Forum
wording: exact_imported_default_with_custom_label
discussion_boundary_preserved: true
citizen_activist_topology_gate: separate_and_open
release_scope_doctrine:
alpha: nearly_feature_complete_for_declared_product_promise
scope_model: cumulative
source_of_truth: existing_dashboard_and_build_launch_checklists
new_gates_displace_existing_gates: false
removal_authority: explicit_Phil_direction
beta_primary_work:
- usability
- compatibility
- reliability
- performance
- packaging
- documentation
- installation
- recovery
- support
- presentation
beta_missing_capability_from_user_evidence: allowed
planned_major_pillar_deferral_to_beta: prohibited_by_default
long_term_and_layer_3_outside_declared_promise: later
tiers:
tier_1:
transport: Discourse_API
plugin_required: false
role: free_self_serve_floor
optional_discourse_plugin:
alpha_vertical_slice_status: installed_and_accepted_on_stable_preproduction_public_release_pending
product_repo: separate_from_Astro_package_per_Boss_routing
license: GPL_2_0_or_later
installability: supported_stock_current_Discourse
accepted_preproduction_Discourse_commit: 36698aae084678151dffa875d49c8d59216d2733
accepted_preproduction_plugin_commit: 50c4a92359f672a00b2242e99819a70813ebea19
removal_and_rollback_docs: required
CAN_normal_topic_baseline: official_Discourse_Mermaid_theme_component
logical_workspace_path: DiscussionBridge/plugins/discourse-discussion-bridge
local_development_root: C:\CodeProjects\Products\DiscussionBridge\plugins\discourse-discussion-bridge
current_installation_state:
host: dev-forum.discussionbridge.dev
role: stable_preproduction
topology: official_split_data_plus_web_only
installed: true
enabled: true
endpoint_at_rest: disabled
core_zero_touch: disabled
comments_only_fullInteractive: enabled
accepted_on: 2026-08-22
production_released: false
core_authority: [authentication, users, topics, posts, permissions, categories, tags, moderation, composer, replies, likes, quotes, edits, notifications, normal_topic_presentation]
first_boundary:
- durable_contract
- default_disabled_plugin
- authenticated_create_or_resolve_interface
- configured_non_system_service_identity
- canonical_connection_plus_absolute_source_URL_identity
- database_unique_mapping_and_audit_interfaces
- requested_vs_effective_policy
- default_unlisted
- fail_closed_no_silent_Core_fallback
- forum_authoritative_actor_category_and_tags
- durable_reservation_and_idempotent_mapping
- controlled_unlisted_topic_creation
- durable_audit
- full_plugin_RSpec_contracts
next_boundary:
kind: human_admin_installs_of_exact_publicly_published_Alpha_tag_and_SHA_from_public_instructions
required_topologies:
- { host: sandbox-forum.discussionbridge.dev, topology: standard_single_container_app }
- { host: dev-forum.discussionbridge.dev, topology: official_split_data_plus_web_only }
separate_acceptance_record_per_host_and_topology: true
forum_repealobbba_org: excluded_from_current_two_proofs_later_separate_OBBBA_authorization_and_recovery_gate
fullInteractive_contract:
accepted_preproduction_state: PASS_installed_migrated_configured_comments_only_ordinary_topic_isolation_admin_operations_and_rollback
early_local_evidence_2026_08_02:
Discourse_commit: 6b2f4579ba6802a7c556459e596c3150b67403aa
non_browser_verification: { rspec: 38_of_38, rubocop: 25_of_25 }
focused_authorization_verification: 7_of_7
browser_verification: 4_of_4_empty_replied_actions_ordinary_long_topic_and_reserved_marker_rejection_PASS
local_development_runtime: PASS_empty_replied_actions_ordinary_topic_option_rollback_and_reserved_marker_rejection
status: historical_qualification_not_current_installation_identity
normal_topic_post_1: unchanged
embedded_post_1_layout_height: zero
preserve: [zero_reply_native_state, replies, login, composer, reply, like, quote, edit, moderation, notifications]
prohibited: [host_height_cap_as_fix, unscoped_theme_CSS, post_1_delete, post_1_rewrite, ordinary_topic_regression]
security:
adapter_values: requests_not_authority
forum_operator_policy: final
credentials_in_docs_logs_or_audit: prohibited
endpoint_default: disabled
plugin_default: disabled
core_zero_touch_compatibility_default: disabled
ordinary_topic_regression: prohibited
live_proof: forum.citizenactivist.network_full_app_embed
not_current_boundary: [admin_UI, existing_topic_migration, arbitrary_impersonation, PM_automation, general_many_to_many, production_installation]
tier_1_dependency: false
controlling_contract: docs/evidence/DISCUSSIONBRIDGE_PLUGIN_V0_1_CONTRACT_2026-08-02.md
multi_target_implementation:
commit: 60e41e1
review: Code_Boss_PASS
tests: 62_of_62_PASS
package_check: PASS
package_dry_run: PASS
frontmatter:
discussionTargets: ordered_CSV_target_names
discussionPublishTargets: explicit_writable_subset_CSV
discussionSourceTarget: explicit_protected_source
discussionTargetBindings: JSON_scalar_map_by_target
discussionPrimaryTarget: required_when_multiple_linked
cli: one_explicit_--target_per_run
publish_on_build: ordered_sequential_lanes
recovery: retain_success_retry_failed_target_idempotently
malformed_binding_state: fail_before_network
public_export: astro-discussion-bridge/targets
connection_job_product_doctrine:
public_lead: Every connection has a job
explicit_human_purpose: required_product_behavior_not_yet_implemented
visible_label_and_CTA_match_purpose: required
independent_replies_silently_merged: prohibited
primary_vs_additional: explicit
later_scope: [relay, promotion, summary]
configuration_design_status: pending_review_not_final_not_implemented
candidate_fields: [role_or_purpose, audience, callToAction, description, visibility_context, direction_source_ownership, presentation]
candidate_roles: [primary-community, public-community, chapter, internal-review, expert-feedback, source-wiki, syndication]
bidirectional_CAN_contract:
directions:
- Astro_managed_page_to_CAN_companion_topic
- CAN_topic_to_Discourse_managed_or_imported_Astro_page
separate_page_topic_pairs: required
explicit_source_ownership: required
same_item_writable_both_directions: prohibited
loop_prevention: single_writer_per_item
chapter_national_future_design:
status: proposed_not_implemented
public_frame: Local ownership. National reach.
topology: governed_hub_and_spoke_federation
supported_directions_to_design:
- local_topic_to_mapped_national_category
- national_guidance_to_selected_local_categories
required_fields:
- source_forum_and_topic
- source_chapter_identity
- parent_child_relationship
- mapped_source_and_destination_categories
- required_tags_region_chapter_metadata
- automatic_or_moderator_approved_promotion
- public_private_eligibility
- source_attribution_and_return_link
- target_specific_title_CTA_description
- one_way_first_post_sync_direction
- independent_reply_streams
- target_specific_failure_retry_idempotency
- moderation_ownership_at_both_levels
optional_later: post_as_chapter_identity
silent_merge_or_ambiguous_writeback: prohibited
current_full_forum_to_forum_orchestration_claim: false
alpha_topology_proof:
status: bounded_OBBBA_to_Citizen_Activist_live_proof_complete
verified_at: 2026-07-22
adoption_commit: 36df91c98a35251edd6ddd657cca42ddf0acdafa
adoption_files:
- src/components/MarkdownContent.astro
- src/content.config.ts
- src/content/docs/title i/10101-impact.mdx
Code_Boss_review: PASS
clean_detached_build: PASS
worker_version: 632db326-bc0d-4047-b74b-7e74d3588dbf
canonical_page: https://onebigbeautifulbill.us/title-i/10101-impact/
canonical_page_HTTP: 200
production_obbba_target: https://forum.repealobbba.org
citizen_activist_target:
canonical: https://forum.citizenactivist.network
public_description: A community of activists
hostname_policy: literal_forum_prefix_identity_in_copy
cloudflare_account_ownership: unresolved_Ops_decision
bounded_demo_target: https://forum.discussionbridge.dev
exact_matrix:
- { from: same_selected_onebigbeautifulbill.us_page, to: https://forum.repealobbba.org }
- { from: same_selected_onebigbeautifulbill.us_page, to: https://forum.citizenactivist.network }
- { from: bounded_demo_credit_pages, to: https://forum.discussionbridge.dev }
- { from: multiple_Astro_public_sites, to: https://forum.repealobbba.org }
proof_meaning:
one_page_multiple_forums: first_two_edges
multiple_sites_one_forum: fourth_edge
contract:
source_target_distinct_from_publication_discussion_targets: required
target_list: explicit_ordered
binding_fields: [topic_id, topic_url, source_hash, last_synced_at, status, last_error, last_attempted_at]
presentation_policy: explicit_primary_plus_accessible_additional_links
source_no_writeback: preserve_for_discourse_imported_and_discourse_managed
comments_presentation: explicit_primary_plus_additional_linked_or_rendered
silent_primary_selection: prohibited
write_semantics: recoverable_partial_success
successful_bindings_on_other_target_failure: retain
retry: target_specific_idempotent_no_duplicate_topics
target_specific_surfaces: [diagnostics, dry_run, CLI_output, manuals, live_proof]
required_gate:
- { target_diagnostics: PASS }
- { target_specific_dry_run: PASS }
- { publish_and_independent_bindings: PASS }
- { unchanged_idempotent_retry: PASS }
- { clean_build_deploy_live_binding: PASS }
- { protected_source_no_writeback: PASS }
exercised_binding:
source_target: repeal-obbba
source_topic_id: 434
source_mode: discourse-imported
discussionSync: false
primary_display: fullInteractive
primary_fullApp: true
publication_target: citizen-activist
publication_topic_id: 9
publication_topic_url: https://forum.citizenactivist.network/t/sec-10101-re-evaluation-of-thrifty-food-plan-impact/9
publication_category: { id: 5, name: One Big Beautiful Bill, slug: one-big-beautiful-bill, public: true }
publication_tags: [discussionbridge, obbba, impact, title-i]
additional_presentation: one_accessible_link
publication_interaction:
posts_count: 2
highest_post_number: 2
last_poster: discourseadmin
Astro_primary_topic_remained: 434
reachability: accessible_Additional_discussions_link
evidence_scope: interaction_and_presentation_only
source_post_count: 12
source_first_post_updated_at: 2026-07-01T01:35:12Z
lane:
docsDir: src/content/docs/title i
route_base: title-i
active_target: citizen-activist
broad_root_dry_run: rejected_before_write_due_to_wrong_index_and_route
dependency_audit:
total: 10
low: 1
moderate: 1
high: 8
resolved: false
action: dependency_review_no_automatic_audit_fix
known_notices: [Starlight_docs_to_404, chunk_size, punycode_deprecation]
temporary_detached_worktree: removed_after_deployment
protected_credentials:
records_exist: true
public_paths_or_values: prohibited
legacy_record_format_cleanup: protected_vault_task
claim: bounded_same_page_OBBBA_to_Citizen_Activist_topology
later_scope: general_many_to_many_administration
release_channel:
Astro_package:
alpha: GitHub_prerelease_plus_exact_attached_tarball
immutable_identity: exact_tag_source_commit_asset_filename_bytes_sha256_inventory
public_install: download_then_SHA256_verify_then_npm_install_--save-exact_same_local_tarball
post_install_proof: lockfile_resolution_names_verified_asset_and_integrity_matches_release_record
source_checkout_or_moving_branch: prohibited_as_release_identity
replace_or_delete_asset_in_place: prohibited
corrected_release: new_prerelease_tag_and_asset
npm_registry_publication: later_separately_authorized_gate
Discourse_plugin:
npm_distribution_decision_applies: false
channel: exact_GitHub_prerelease_tag_and_commit
required_for: plugin_backed_fullInteractive_and_forum_control_plane
not_required_for: [simple, full]
human_install_acceptance:
required_before_product_release_acceptance_closes: true
actor: human_Discourse_administrator
input: public_release_instructions_only
required_proofs:
- { host: sandbox-forum.discussionbridge.dev, topology: standard_single_container, action: containers/app.yml_then_rebuild_app }
- { host: dev-forum.discussionbridge.dev, topology: official_split_data_plus_web_only, action: containers/web_only.yml_then_rebuild_web_only_only }
separate_acceptance_record_per_host_and_topology: true
forum_repealobbba_org: excluded_from_current_two_proofs_later_separate_OBBBA_authorization_and_recovery_gate
initial_settings: all_safe_defaults_off
proof: [backup_identity, installed_SHA, migrations, ordinary_forum_health, enable_configure, disable_rollback_removal]
failure: new_corrected_prerelease_never_rewrite_existing_identity
alpha_feature_lock:
status: locked
cumulative_scope_source: docs/BUILD_LAUNCH_CHECKLISTS.md
allowed_new_work:
- close_existing_promise_or_gate
- fix_exercised_behavior
- explicitly_approved_scope_change
software_tracks:
astro_package: free_open_source
discussionbridge_for_discourse_plugin: free_open_source
public_docs_and_community_support: free_open_source
paid_value:
- implementation_help
- handholding
- managed_hosting_and_operations
- customization
- support
- consulting
third_party_infrastructure: operator_paid
discussionbridge_dev_dogfood:
reviewed_import_support:
commit: 1731547
code_boss: PASS
tests: 72/72
source_modes: [discourse-imported, discourse-managed]
default: discourse-imported
rejected: [astro-managed]
manifest_field: sourceMode
discussionSync: false
artifact: astro-discussion-bridge-0.1.0-alpha-1731547-7d8951d1.tgz
sha256: 7d8951d15f4b0a4a4f14e238665bc41c28255c6f2cdcb1979105926ba6f4affb
node_engine: ">=22.12.0"
guide_dry_run:
source_forum: https://forum.discussionbridge.dev
source_topic_id: 36
destination_route: /guides/how-to-choose-a-discussion-bridge-source-mode/
status: passed
live_gate:
status: complete_bounded_two_direction_proof
apex_commit: d68ffc4
code_boss: PASS
clean_detached_build_routes: 5
deployed_at: 2026-07-23T09:00:47-07:00
apex_http: 200
pages_hostname: https://discussionbridge-dev.pages.dev
pages_hostname_redirect: 301_to_apex
blog:
route: /blog/every-connection-has-a-job/
http: 200
topic_id: 37
category_id: 5
wiki: false
tags: [discussionbridge, community, product]
guide:
route: /guides/how-to-choose-a-discussion-bridge-source-mode/
http: 200
topic_id: 36
category_id: 6
wiki: true
tags: [discussionbridge, source-mode, guide]
source_disclosure: verified
primary_comments: fullInteractive
sync_existing_dry_run: skipped_discourse_managed_no_writeback
npm_audit: { high: 1, automatic_fix: prohibited_not_run }
known_warning: Mermaid_chunk_over_500k
topic_36_editor_ownership_acceptance:
status: open
required:
- change_first_post_owner_from_discourseadmin_to_selected_bridge_forum_editor
- edit_wiki_as_selected_editor
- import_refresh_discourse_managed_guide_with_overwrite
- verify_content_and_source_ownership
- build_deploy_and_verify_live_markers
- prove_no_Astro_writeback
source_author_provenance:
import_fields:
- discussionSourceAuthorUsername
- discussionSourceAuthorName
overwrite_refresh: update_from_current_Discourse_first_post_author
preserved_on_refresh:
- discussionSourceMode
- discussionSync_false
- discourseTopicId
rendered_notice: "Source author: Display Name (@username)"
profile_link: same_forum_base_preserving_safe_/u/username
subfolder_example:
topic: https://example.com/forum/t/example/123
profile: https://example.com/forum/u/editorbridgeforum
unsafe_username_behavior: omit_author_metadata_and_link
request_actor_regressions:
- real_CLI_execution_with_--post-as
- dry-run_actor_output
package_suite: 79/79
category_contract:
generated_source_field: discussionSourceCategoryId
comparison_source: existing_opening_YAML_frontmatter_only
parser_safety: [LF, CRLF, BOM, ignore_body_and_code_block_lookalikes]
change_reason: "source category changed: OLD -> NEW; Astro route/navigation unchanged"
evaluated_during:
- existing_file_skip
- dry_run_overwrite
- live_overwrite
overwrite_effect:
WHEREFROM: refresh_source_category_metadata
WHERETO: preserve_output_file_public_route_and_Astro_navigation_lane
manifest_contract:
- direct_and_strict_atomic_flows
- preserve_reason_in_dry_run_and_live_overwrite
- preserve_stable_output_path
- preserve_source_mode
- preserve_discussionSync_false
- preserve_topic_ID_and_source_protections
CLI: print_change_reason
example_schemas: [Astro, Starlight]
astro_managed:
configured_category: authoritative_sync_corrects_drift
no_configured_category: preserve_manual_Discourse_category
discourse_managed_or_imported_source:
category_writeback: prohibited
multi_target:
target_categories: independent
evidence_record: docs/evidence/DISCUSSIONBRIDGE_DEV_TWO_WAY_DOGFOOD_2026-07-23.md
count_boundary:
apex_generated_public_routes: 5
docs_synced_sources: 20
docs_generated_html_pages: 21
direction_1:
source: discussionbridge.dev_Astro_managed_blog
destination: forum.discussionbridge.dev_public_companion_topic
writer: Astro
direction_2:
source: forum.discussionbridge.dev_community_wiki
destination: discussionbridge.dev_durable_public_guide
source_mode: discourse-managed
discussionSync: false
source_provenance: required
refresh: deterministic_reviewed_source
destination_contract: explicit_public_route_and_Astro_navigation_lane
primary_discussion: source_forum_topic
writer: Discourse_wiki
reply_streams: independent_never_merged
public_outcome: The site starts conversations. The community develops durable knowledge. The site publishes what the community learns.
support:
formal_work: GitHub Issues
setup_and_field_reports: Discourse Alpha Support category
email_intake:
address: alphasupport@discussionbridge.dev
destination: Discourse
status: planned_pending_verified_route
private_help: paid implementation/migration
attribution_and_licensing:
implementation:
script: scripts/check-attribution.mjs
inventory: docs/THIRD_PARTY_PROVENANCE.json
reviewed_override_evidence: docs/third-party-licenses/khroma-2.1.0-MIT.txt
fresh_checkout_sync:
executable: process.execPath
shell: false
regression: passed
full_package_gate:
command: npm run check:attribution
included_in_package_suite: exact_candidate_total_required
status: PASS
checks:
- root_package_MIT_parity_and_holder
- package_license_metadata
- production_lock_dependency_license_allowlist_or_reviewed_override
- npm_pack_required_contents
- README_non_affiliation_and_rendered_links
- tracked_media_provenance
- protected_path_scan
docs_scope_gate:
command: npm run check:attribution --docs-scope
required_status: PASS (docs scope)
npm_package_contents: SKIPPED (requires built release candidate)
docs_result: exact_candidate_synced_source_and_HTML_counts_required
reporting_invariant: full_package_gate_and_docs_scope_gate_are_not_interchangeable
manual_boss:
required_result: "Attribution and Licensing: PASS / FAIL / N/A"
reviewed_paths: required
sanitized_exact_release_record: required
current_status: PASS
exact_candidate: b09dbce
commit_chain: [7127eb1, 462b3ae, b09dbce]
remaining_findings: 0
record: docs/evidence/ATTRIBUTION_LICENSING_REVIEW_B09DBCE_2026-07-23.md
release_prerequisites:
- exact GitHub prerelease tag and reviewed source commit selected
- exact attached tarball filename, bytes, SHA-256, and file inventory recorded
- clean install of that same immutable tarball in supported Astro and Starlight consumers
- exports, Astro components, CLI bin/help, import/sync, comments, source disclosure, and multi-target helpers verified
- LICENSE, README, repository, bugs, and homepage metadata verified
- credentials, fixtures, local paths, and unintended files absent
- Code Boss pass/fail result recorded against the exact release candidate
- blocking code-review edits complete and re-reviewed where required
- Bridge Boss technical verification complete
- Manual Boss quality review complete
- Human and Machine Manuals ready for the exact release
- Product Boss documentation sign-off recorded
- Product Boss release approval recorded
- live Alpha Support category verified
- email route verified
- README, docs, metadata, demos, and release notes agree
- GitHub prerelease tag, source commit, release asset, and recorded hash agree
- public install from the hash-verified local release asset and matching lockfile integrity verified
- human Discourse administration installs the exact published plugin candidate from public instructions on sandbox-forum.discussionbridge.dev as standard single-container app and on dev-forum.discussionbridge.dev as official split data plus web_only
- separate human plugin acceptance for each named host/topology proves rollback identity, installed SHA, migrations, safe-default startup, ordinary forum health, enable/configure, and disable/rollback/removal
- v0.1.0-alpha.5 is immutable rejected_do_not_install evidence because its human gate found an unreachable synthetic embedded logout trigger and paired adapter clipping
- corrected auth acceptance uses signed_out_initial_state, Core_popup_signin, new_user_signup, and separately_induced_Core_owned_session_loss_then_known_Astro_page_reload; Open_discussion_is_not_logout
- corrected frame acceptance proves topic_progress, lower_frame_scroll, composer_open_close, and credit_below_complete_iframe without a competing CSS viewport ceiling
- forum.repealobbba.org is excluded from these two current proofs and remains a later separately authorized independent real-world gate
- upgrade, downgrade, rollback, supersession, and recovery procedure verified
- bad assets are warned and superseded by a new tag, never replaced or deleted in place
- automatic npm audit fix prohibited
- package tests and demo build pass
- dry-run CLI checks pass
- at least one controlled live smoke sync passes

Support bundles may include package/framework versions, sanitized commands and output, lane name, public URLs, category ID, tags, key type, and dry-run result. They must not include key values, credentials, private account data, or production secrets.

Status: official-source navigation contract implemented and package tests 113/113 PASS; exact OBBBA Text candidate reviewed, deployment not authorized.

navigation_taxonomy_contract:
product_principle: complete_structure_progressive_presentation
authority_by_lane:
official_source_lane:
authority: authoritative_external_official_source
defines: [scope, hierarchy, order, labels, local_routes]
forum_join: after_official_inventory_only
forum_authored_lane:
inputs: [categories, tag_groups, index_topics, content_topic_tags]
tag_group_membership_order_canonical: false
node_contract:
local_or_group_node:
topic_required: false
must_have: local_URL_or_children
forum_linked_node:
must_have_together: [topicId, sourceUrl]
partial_binding: fail_closed
synthetic_topic_for_navigation: prohibited
generated_artifact:
kind: canonical_navigation_taxonomy_manifest
consumers: [Starlight_adapter, plain_Astro_adapter]
presentation:
global: [content_lenses, Titles]
expanded: [current_lens, current_Title, active_descendant_branch]
collapsed_user_expandable: other_branches
complete_browse_surface: index_pages
supporting_navigation: [breadcrumbs, authored_previous_next, search]
avoid:
- hundreds_of_inactive_Title_VII_links_visible_on_every_route
- unnecessary_inactive_deep_branch_DOM
candidate_modes_not_config_contract: [progressive, complete, compact]
responsive_accessibility:
viewports: [desktop, laptop, tablet, mobile]
scale_case: Title_VII
drawer_opens_active_branch: required
keyboard_and_screen_reader: required
preserve_expansion_where_appropriate: required
proposed_routes:
- /obbba-text/title-i/...
- /impact/title-i/...
redirects_required_at_design_stage: false
implementation_evidence:
package_tests: { status: PASS, count: 113 }
OBBBA_Text_candidate:
source: GovInfo_PLAW-119publ21
official_sections: 310
local_routes: 310
optional_complete_forum_bindings: 307
official_without_forum_binding: [1, 20009, 71119]
section_70310: absent
forum_inventory_309_used_as_official_cardinality: false
sitemap: { URLs: 331, unique: 331, missing_official_navigation_URLs: 0 }
encoded_space_routes: 0
publicationAuthorized: false
deploymentAuthorized: false
presentation:
component: DiscussionNavigation
adapters: [Starlight_sidebar, plain_Astro]
hierarchy_without_synthetic_topics: PASS
Impact_preserved_local_routes: 15
open:
- exact_deployment_and_live_acceptance
- Law_as_Amended

Do not derive an official-source lane from forum categories, tag groups, topics, bodies, indexes, or counts. Do not manufacture tags or topics for a local hierarchy. Forum-authored lanes may retain their own reviewed discovery rules, but every claimed forum connection must be complete and optional joins must follow authoritative scope establishment.

17. Official-Source Enrichment And Relations

Section titled “17. Official-Source Enrichment And Relations”

Status: package implemented at e775af3 plus bc8acb5 and db1c57a; bounded Section 10101 refreshed live at OBBBA 5a455f1; final zero-write OBBBA Text batch comparison completed 2026-07-24.

official_source_enrichment:
content_source:
role: protected_Discourse_source_topic
wiki_status: optional_metadata
ownership_and_no_writeback_basis: source_mode_contract
official_text:
authority: authoritative_public_record
identity: [document_or_law, sectionId, label]
locator: [structural_identifier, citation, official_page_range]
URLs: [overview, structured_text, text_fallback, visual_record]
evidence: [checkedAt, sourceHash, comparisonResult]
OBBBA:
document: Public Law 119-21
overview: Congress.gov_text_page
structured_text: USLM_XML
page_marker_fallback: official_TXT
visual_verification: official_PDF
citation_rule: Statutes_at_Large_pages_not_PDF_file_pages
match_policy:
missing_or_duplicate_or_ambiguous: fail_closed_or_review
silent_community_text_rewrite: prohibited
comparison_results: [exact, presentation-only, substantive-difference, unresolved]
presentation_only_may_ignore:
- Markdown_links
- whitespace_and_line_wrap
- typographic_punctuation
- official_page_furniture
- official_side_notes
presentation_only_must_preserve: [substantive_wording, numbering]
capitalization_only:
normalized_case: preserved
classification: substantive-difference
path: review_or_explicit_per_entry_override
reason: may_identify_legal_defined_terms_or_identifiers
batch_mode: { report_all_result_counts: true, content_writes: 0 }
bounded_field_evidence:
Discourse: { topic_id: 34, post_id: 40 }
section: 10101
USLM_id: /us/pl/119/21/tI/stA/s10101
normalized: { tokens_each: 608, characters_each: 3148, substantive_differences: 0 }
citation: Public Law 119-21, Section 10101, 139 Stat. 80-81
scope: representative_single_section_not_batch_claim
relationship_graph:
aggregate_cardinality: many_to_many
stable_key: sectionId
lenses: [OBBBA Text, Law as Amended, Impact, Stories]
reciprocal_links: generated
directional_views:
section_to_Stories: one_to_many
Story_to_sections: one_to_many
update_operation: regenerate_manifest_then_Astro_build
body_reimport_required: false
manual_per_page_links: prohibited
adapters: [Starlight, plain_Astro]
provenance_and_authority_separate_from_related_navigation: true
law_as_amended_authority:
reset_date: 2026-07-27
legacy_implementation:
disposition: inert_lessons_learned_only
repair_base: false
salvage_authorized: false
prohibited_inputs:
- legacy_code_tests_schemas_fixtures
- legacy_parsers_caches_generated_evidence
- forum_derived_scope_or_cardinality
- derivative_source_models
clean_room:
placement: OBBBA_specific_site_adapter_evidence
portable_Core: false
reusable_Astro_package: false
admitted_legacy_imports: 0
admitted_legacy_artifacts: 0
salvaged_assets: 0
authority_order:
- authoritative_official_source_discovery
- preserve_raw_identity_retrieval_bytes_hashes
- neutral_parse
- reviewed_official_scope_and_legal_state
- Astro_presentation
- optional_forum_context_and_discussion
forum_allowed_after_official_scope:
- optional_verbatim_title
- optional_tags_category_authored_index
- optional_legislative_drafting_context
- optional_topic_and_discussion_binding
forum_prohibited:
- legal_body_authority
- official_scope
- official_cardinality
settled_invariants:
section_20009: present_mandatory
section_70310: phil_boss_settled_does_not_exist_no_targeted_search
section_71119: official_source_first_binding
forum_count_309: identity_discussion_inventory_only
contradiction: BLOCKED_DOCTRINE_EVIDENCE_CONFLICT
publication_authorized: false
gate_2_authorized: false
portable_adoption_authorized: false
implementation_evidence:
profile: us-public-law
manifest_version: 2
URL_policy: HTTPS_congress_gov_or_www_through_final_redirect
overwrite_policy:
no_overwrite_skip_before: [raw_post_read, official_source_read]
substantive_result: explicit_per_entry_override_only
source_tags_field: discussionSourceTags_JSON_scalar
component: DiscussionRelations
relationship_manifest: virtual_rebuild_time
package_tests: 107/107
npm_run_check: PASS
npm_pack:
files: 52
bytes: 86864
artifact:
file: astro-discussion-bridge-0.1.0-alpha-db1c57a-17b3dba9.tgz
SHA256: 17b3dba90891f8a5222389dd351bfb5904ab8c5a32e53dd86745233dda452eb4
core_Astro_build: { status: PASS, public_routes: 3 }
importer_fixture: non_routed_scalar_frontmatter_validated
open:
- batch_comparison_review_and_approved_population_manifest
- additional_OBBBA_Text_and_lenses
- Law_as_Amended_adoption
- broader_Title_VII_scale_and_accessibility_as_content_expands
- dependency_vulnerability_review
OBBBA_current_candidate:
official_sections: 310
optional_complete_forum_bindings: 307
official_without_forum_binding: [1, 20009, 71119]
section_70310: absent
sitemap_routes: 331
Impact_preserved_local_routes: 15
publicationAuthorized: false
deploymentAuthorized: false
publishOnBuild: false
Discourse_writes: 0
public_429_policy:
tag_group_reads: sequential
retry_statuses: [429]
max_retries: 3
Retry_After: [seconds_capped, date_capped, fallback_delay]
rejected_body_cancel_bound_ms: 50
retry_403: false

The public-accountability chain is official record → structured section → legal/practical analysis → human consequences → community scrutiny/correction. Do not claim implementation completion from the single-section comparison.

docs_page_metadata:
implementation_commit: 02206f7
ledger: docs/DOCS_PAGE_METADATA.json
ledger_entry: [lastUpdated, SHA-256]
membership: exact_synchronized_source_set
date_meaning: canonical_source_last_verified_change
prohibited_date_sources: [build_timestamp, deploy_timestamp, Git_history]
normal_build:
refreshes_dates: false
fail_closed: [missing_entry, stale_extra_entry, byte_hash_mismatch]
explicit_refresh:
cwd: sites/docs
command: npm run refresh-metadata
unchanged_source: preserve_date
changed_source: update_date_and_hash
new_source: initialize_entry
removed_source: remove_entry
prebuild_order:
- metadata_tests
- sync_content
- attribution_docs_scope
rendered_contract:
title_row:
- "Last updated: verified source date"
- "Applies to: DiscussionBridge Alpha"
footer:
- Last_updated_only
- exact_canonical_GitHub_edit_link
responsive: [desktop_1440_PASS, mobile_390_PASS]
verification:
metadata_tests: 2/2
docs_sources: 21
HTML_pages: 22
attribution_docs_scope: PASS
semantic_review_replaced: false

Run refresh only after intentional canonical documentation edits. Commit the changed canonical docs and ledger together. Do not treat synchronized site content as the source of truth, and do not use metadata verification as a substitute for Manual Boss review.

When implementation confirms or changes a command, field, scope, endpoint, failure, recovery path, or deployment invariant:

  1. update this machine manual;
  2. update the corresponding human instruction when operator behavior changes;
  3. update the focused guide or checklist;
  4. route implementation gaps to Bridge Boss and manual-quality review to Manual Boss.