diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index a50068f1d7..37c3bede9c 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -5,7 +5,7 @@
 	"workspaceFolder": "/workspace",
 	"features": {
 		"ghcr.io/devcontainers-contrib/features/pnpm:2": {
-			"version": "8.9.2"
+			"version": "latest"
 		},
 		"ghcr.io/devcontainers/features/node:1": {
 			"version": "20"
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 19675bd910..e35a37e593 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -17,10 +17,12 @@
 ### General
 - Feat: メールアドレスの認証にverifymail.ioを使えるように (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/971ba07a44550f68d2ba31c62066db2d43a0caed)
 - Feat: モデレーターがユーザーのアイコンもしくはバナー画像を未設定状態にできる機能を追加 (cherry-pick from https://github.com/TeamNijimiss/misskey/commit/e0eb5a752f6e5616d6312bb7c9790302f9dbff83)
+- Feat: TL上からノートが見えなくなるワードミュートであるハードミュートを追加
 - Fix: MFM `$[unixtime ]` に不正な値を入力した際に発生する各種エラーを修正
 
 ### Client
 - Enhance: 絵文字のオートコンプリート機能強化 #12364
+- Enhance: ユーザーのRawデータを表示するページが復活
 - fix: 「設定のバックアップ」で一部の項目がバックアップに含まれていなかった問題を修正
 - Fix: ウィジェットのジョブキューにて音声の発音方法変更に追従できていなかったのを修正 #12367
 - Fix: コードエディタが正しく表示されない問題を修正
@@ -32,6 +34,7 @@
 - Fix: ロールタイムラインが保存されない問題を修正
 - Fix: api.jsonの生成ロジックを改善 #12402
 - Fix: 招待コードが使い回せる問題を修正
+- Fix: 特定の条件下でチャンネルやユーザーのノート一覧に最新のノートが表示されなくなる問題を修正
 
 ## 2023.11.1
 
diff --git a/locales/index.d.ts b/locales/index.d.ts
index a26d45c843..958bd066f7 100644
--- a/locales/index.d.ts
+++ b/locales/index.d.ts
@@ -1042,6 +1042,7 @@ export interface Locale {
     "enableChartsForFederatedInstances": string;
     "showClipButtonInNoteFooter": string;
     "reactionsDisplaySize": string;
+    "limitWidthOfReaction": string;
     "noteIdOrUrl": string;
     "video": string;
     "videos": string;
@@ -1648,7 +1649,9 @@ export interface Locale {
         "assignTarget": string;
         "descriptionOfAssignTarget": string;
         "manual": string;
+        "manualRoles": string;
         "conditional": string;
+        "conditionalRoles": string;
         "condition": string;
         "isConditionalRole": string;
         "isPublic": string;
diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml
index 4684bc0cfc..8651bd92d7 100644
--- a/locales/ja-JP.yml
+++ b/locales/ja-JP.yml
@@ -1039,6 +1039,7 @@ enableChartsForRemoteUser: "リモートユーザーのチャートを生成"
 enableChartsForFederatedInstances: "リモートサーバーのチャートを生成"
 showClipButtonInNoteFooter: "ノートのアクションにクリップを追加"
 reactionsDisplaySize: "リアクションの表示サイズ"
+limitWidthOfReaction: "リアクションの最大横幅を制限し、縮小して表示する"
 noteIdOrUrl: "ノートIDまたはURL"
 video: "動画"
 videos: "動画"
@@ -1558,7 +1559,9 @@ _role:
   assignTarget: "アサイン"
   descriptionOfAssignTarget: "<b>マニュアル</b>は誰がこのロールに含まれるかを手動で管理します。\n<b>コンディショナル</b>は条件を設定し、それに合致するユーザーが自動で含まれるようになります。"
   manual: "マニュアル"
+  manualRoles: "マニュアルロール"
   conditional: "コンディショナル"
+  conditionalRoles: "コンディショナルロール"
   condition: "条件"
   isConditionalRole: "これはコンディショナルロールです。"
   isPublic: "公開ロール"
diff --git a/packages/backend/src/server/api/endpoints/channels/timeline.ts b/packages/backend/src/server/api/endpoints/channels/timeline.ts
index fae4249c8a..4ca7325f30 100644
--- a/packages/backend/src/server/api/endpoints/channels/timeline.ts
+++ b/packages/backend/src/server/api/endpoints/channels/timeline.ts
@@ -15,6 +15,7 @@ import { IdService } from '@/core/IdService.js';
 import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
 import { isUserRelated } from '@/misc/is-user-related.js';
 import { CacheService } from '@/core/CacheService.js';
+import { MetaService } from '@/core/MetaService.js';
 import { ApiError } from '../../error.js';
 
 export const meta = {
@@ -72,12 +73,15 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 		private funoutTimelineService: FunoutTimelineService,
 		private cacheService: CacheService,
 		private activeUsersChart: ActiveUsersChart,
+		private metaService: MetaService,
 	) {
 		super(meta, paramDef, async (ps, me) => {
 			const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
 			const sinceId = ps.sinceId ?? (ps.sinceDate ? this.idService.gen(ps.sinceDate!) : null);
 			const isRangeSpecified = untilId != null && sinceId != null;
 
+			const serverSettings = await this.metaService.fetch();
+
 			const channel = await this.channelsRepository.findOneBy({
 				id: ps.channelId,
 			});
@@ -88,7 +92,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 
 			if (me) this.activeUsersChart.read(me);
 
-			if (isRangeSpecified || sinceId == null) {
+			if (serverSettings.enableFanoutTimeline && (isRangeSpecified || sinceId == null)) {
 				const [
 					userIdsWhoMeMuting,
 				] = me ? await Promise.all([
diff --git a/packages/backend/src/server/api/endpoints/notes/create.ts b/packages/backend/src/server/api/endpoints/notes/create.ts
index 33f3f5655d..ea483b9b54 100644
--- a/packages/backend/src/server/api/endpoints/notes/create.ts
+++ b/packages/backend/src/server/api/endpoints/notes/create.ts
@@ -263,7 +263,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 				if (renote.channelId && renote.channelId !== ps.channelId) {
 					// チャンネルのノートに対しリノート要求がきたとき、チャンネル外へのリノート可否をチェック
 					// リノートのユースケースのうち、チャンネル内→チャンネル外は少数だと考えられるため、JOINはせず必要な時に都度取得する
-					const renoteChannel = await this.channelsRepository.findOneById(renote.channelId);
+					const renoteChannel = await this.channelsRepository.findOneBy({ id: renote.channelId });
 					if (renoteChannel == null) {
 						// リノートしたいノートが書き込まれているチャンネルが無い
 						throw new ApiError(meta.errors.noSuchChannel);
diff --git a/packages/backend/src/server/api/endpoints/users/notes.ts b/packages/backend/src/server/api/endpoints/users/notes.ts
index 02be8bb93c..415ae42d3f 100644
--- a/packages/backend/src/server/api/endpoints/users/notes.ts
+++ b/packages/backend/src/server/api/endpoints/users/notes.ts
@@ -15,6 +15,7 @@ import { IdService } from '@/core/IdService.js';
 import { isUserRelated } from '@/misc/is-user-related.js';
 import { QueryService } from '@/core/QueryService.js';
 import { FunoutTimelineService } from '@/core/FunoutTimelineService.js';
+import { MetaService } from '@/core/MetaService.js';
 import { ApiError } from '../../error.js';
 
 export const meta = {
@@ -71,6 +72,7 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 		private cacheService: CacheService,
 		private idService: IdService,
 		private funoutTimelineService: FunoutTimelineService,
+		private metaService: MetaService,
 	) {
 		super(meta, paramDef, async (ps, me) => {
 			const untilId = ps.untilId ?? (ps.untilDate ? this.idService.gen(ps.untilDate!) : null);
@@ -78,7 +80,9 @@ export default class extends Endpoint<typeof meta, typeof paramDef> { // eslint-
 			const isRangeSpecified = untilId != null && sinceId != null;
 			const isSelf = me && (me.id === ps.userId);
 
-			if (isRangeSpecified || sinceId == null) {
+			const serverSettings = await this.metaService.fetch();
+
+			if (serverSettings.enableFanoutTimeline && (isRangeSpecified || sinceId == null)) {
 				const [
 					userIdsWhoMeMuting,
 				] = me ? await Promise.all([
diff --git a/packages/frontend/src/components/MkAbuseReport.vue b/packages/frontend/src/components/MkAbuseReport.vue
index 66114b8734..2c7be319cb 100644
--- a/packages/frontend/src/components/MkAbuseReport.vue
+++ b/packages/frontend/src/components/MkAbuseReport.vue
@@ -23,7 +23,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<Mfm :text="report.comment"/>
 		</div>
 		<hr/>
-		<div>{{ i18n.ts.reporter }}: <MkAcct :user="report.reporter"/></div>
+		<div>{{ i18n.ts.reporter }}: <MkA :to="`/admin/user/${report.reporter.id}`" class="_link">@{{ report.reporter.username }}</MkA></div>
 		<div v-if="report.assignee">
 			{{ i18n.ts.moderator }}:
 			<MkAcct :user="report.assignee"/>
diff --git a/packages/frontend/src/components/MkReactionsViewer.reaction.vue b/packages/frontend/src/components/MkReactionsViewer.reaction.vue
index 2b850016c5..9a107c3674 100644
--- a/packages/frontend/src/components/MkReactionsViewer.reaction.vue
+++ b/packages/frontend/src/components/MkReactionsViewer.reaction.vue
@@ -11,7 +11,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 	:class="[$style.root, { [$style.reacted]: note.myReaction == reaction, [$style.canToggle]: canToggle, [$style.small]: defaultStore.state.reactionsDisplaySize === 'small', [$style.large]: defaultStore.state.reactionsDisplaySize === 'large' }]"
 	@click="toggleReaction()"
 >
-	<MkReactionIcon :class="$style.icon" :reaction="reaction" :emojiUrl="note.reactionEmojis[reaction.substring(1, reaction.length - 1)]"/>
+	<MkReactionIcon :class="defaultStore.state.limitWidthOfReaction ? $style.limitWidth : ''" :reaction="reaction" :emojiUrl="note.reactionEmojis[reaction.substring(1, reaction.length - 1)]"/>
 	<span :class="$style.count">{{ count }}</span>
 </button>
 </template>
@@ -188,7 +188,7 @@ if (!mock) {
 	}
 }
 
-.icon {
+.limitWidth {
 	max-width: 150px;
 }
 
diff --git a/packages/frontend/src/pages/admin/roles.vue b/packages/frontend/src/pages/admin/roles.vue
index d87d584daa..9f6c400fac 100644
--- a/packages/frontend/src/pages/admin/roles.vue
+++ b/packages/frontend/src/pages/admin/roles.vue
@@ -222,13 +222,13 @@ SPDX-License-Identifier: AGPL-3.0-only
 				<MkButton primary rounded @click="create"><i class="ti ti-plus"></i> {{ i18n.ts._role.new }}</MkButton>
 				<div class="_gaps_s">
 					<MkFoldableSection>
-						<template #header>Manual roles</template>
+						<template #header>{{ i18n.ts._role.manualRoles }}</template>
 						<div class="_gaps_s">
 							<MkRolePreview v-for="role in roles.filter(x => x.target === 'manual')" :key="role.id" :role="role" :forModeration="true"/>
 						</div>
 					</MkFoldableSection>
 					<MkFoldableSection>
-						<template #header>Conditional roles</template>
+						<template #header>{{ i18n.ts._role.conditionalRoles }}</template>
 						<div class="_gaps_s">
 							<MkRolePreview v-for="role in roles.filter(x => x.target === 'conditional')" :key="role.id" :role="role" :forModeration="true"/>
 						</div>
diff --git a/packages/frontend/src/pages/settings/general.vue b/packages/frontend/src/pages/settings/general.vue
index 06d3789829..313b5efc46 100644
--- a/packages/frontend/src/pages/settings/general.vue
+++ b/packages/frontend/src/pages/settings/general.vue
@@ -56,6 +56,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 					<option value="medium">{{ i18n.ts.medium }}</option>
 					<option value="large">{{ i18n.ts.large }}</option>
 				</MkRadios>
+				<MkSwitch v-model="limitWidthOfReaction">{{ i18n.ts.limitWidthOfReaction }}</MkSwitch>
 			</div>
 
 			<MkSelect v-model="instanceTicker">
@@ -226,6 +227,7 @@ const serverDisconnectedBehavior = computed(defaultStore.makeGetterSetter('serve
 const showNoteActionsOnlyHover = computed(defaultStore.makeGetterSetter('showNoteActionsOnlyHover'));
 const showClipButtonInNoteFooter = computed(defaultStore.makeGetterSetter('showClipButtonInNoteFooter'));
 const reactionsDisplaySize = computed(defaultStore.makeGetterSetter('reactionsDisplaySize'));
+const limitWidthOfReaction = computed(defaultStore.makeGetterSetter('limitWidthOfReaction'));
 const collapseRenotes = computed(defaultStore.makeGetterSetter('collapseRenotes'));
 const reduceAnimation = computed(defaultStore.makeGetterSetter('animation', v => !v, v => !v));
 const useBlurEffectForModal = computed(defaultStore.makeGetterSetter('useBlurEffectForModal'));
@@ -290,6 +292,7 @@ watch([
 	overridedDeviceKind,
 	mediaListWithOneImageAppearance,
 	reactionsDisplaySize,
+	limitWidthOfReaction,
 	highlightSensitiveMedia,
 	keepScreenOn,
 	disableStreamingTimeline,
diff --git a/packages/frontend/src/pages/user/index.vue b/packages/frontend/src/pages/user/index.vue
index 7550d5bcb2..50cc9a3311 100644
--- a/packages/frontend/src/pages/user/index.vue
+++ b/packages/frontend/src/pages/user/index.vue
@@ -18,6 +18,7 @@ SPDX-License-Identifier: AGPL-3.0-only
 			<XPages v-else-if="tab === 'pages'" :user="user"/>
 			<XFlashs v-else-if="tab === 'flashs'" :user="user"/>
 			<XGallery v-else-if="tab === 'gallery'" :user="user"/>
+			<XRaw v-else-if="tab === 'raw'" :user="user"/>
 		</div>
 		<MkError v-else-if="error" @retry="fetchUser()"/>
 		<MkLoading v-else/>
@@ -44,6 +45,7 @@ const XLists = defineAsyncComponent(() => import('./lists.vue'));
 const XPages = defineAsyncComponent(() => import('./pages.vue'));
 const XFlashs = defineAsyncComponent(() => import('./flashs.vue'));
 const XGallery = defineAsyncComponent(() => import('./gallery.vue'));
+const XRaw = defineAsyncComponent(() => import('./raw.vue'));
 
 const props = withDefaults(defineProps<{
 	acct: string;
@@ -112,6 +114,10 @@ const headerTabs = $computed(() => user ? [{
 	key: 'gallery',
 	title: i18n.ts.gallery,
 	icon: 'ti ti-icons',
+}, {
+	key: 'raw',
+	title: 'Raw',
+	icon: 'ti ti-code',
 }] : []);
 
 definePageMetadata(computed(() => user ? {
diff --git a/packages/frontend/src/pages/user/raw.vue b/packages/frontend/src/pages/user/raw.vue
new file mode 100644
index 0000000000..0c0bfc29ca
--- /dev/null
+++ b/packages/frontend/src/pages/user/raw.vue
@@ -0,0 +1,130 @@
+<!--
+SPDX-FileCopyrightText: syuilo and other misskey contributors
+SPDX-License-Identifier: AGPL-3.0-only
+-->
+
+<template>
+<MkSpacer :contentMax="600" :marginMin="16" :marginMax="32">
+	<div class="_gaps_m">
+		<div :class="$style.userMInfoRoot">
+			<MkAvatar :class="$style.userMInfoAvatar" :user="user" indicator link preview/>
+			<div :class="$style.userMInfoMetaRoot">
+				<span :class="$style.userMInfoMetaName"><MkUserName :class="$style.userMInfoMetaName" :user="user"/></span>
+				<span :class="$style.userMInfoMetaSub"><span class="acct _monospace">@{{ acct(user) }}</span></span>
+				<span :class="$style.userMInfoMetaState">
+					<span v-if="suspended" :class="$style.suspended">Suspended</span>
+					<span v-if="silenced" :class="$style.silenced">Silenced</span>
+					<span v-if="moderator" :class="$style.moderator">Moderator</span>
+				</span>
+			</div>
+		</div>
+
+		<div style="display: flex; flex-direction: column; gap: 1em;">
+			<MkKeyValue :copy="user.id" oneline>
+				<template #key>ID</template>
+				<template #value><span class="_monospace">{{ user.id }}</span></template>
+			</MkKeyValue>
+			<MkKeyValue oneline>
+				<template #key>{{ i18n.ts.createdAt }}</template>
+				<template #value><span class="_monospace"><MkTime :time="user.createdAt" :mode="'detail'"/></span></template>
+			</MkKeyValue>
+		</div>
+
+		<FormSection>
+			<template #label>Raw</template>
+			<MkObjectView tall :value="user"></MkObjectView>
+		</FormSection>
+	</div>
+</MkSpacer>
+</template>
+
+<script lang="ts" setup>
+import { computed } from 'vue';
+import * as Misskey from 'misskey-js';
+import { acct } from '@/filters/user.js';
+import { i18n } from '@/i18n.js';
+import MkKeyValue from '@/components/MkKeyValue.vue';
+import FormSection from '@/components/form/section.vue';
+import MkObjectView from '@/components/MkObjectView.vue';
+
+const props = defineProps<{
+	user: Misskey.entities.User;
+}>();
+
+const moderator = computed(() => props.user.isModerator ?? false);
+const silenced = computed(() => props.user.isSilenced ?? false);
+const suspended = computed(() => props.user.isSuspended ?? false);
+</script>
+
+<style lang="scss" module>
+.userMInfoRoot {
+	display: flex;
+	align-items: center;
+}
+
+.userMInfoAvatar {
+	display: block;
+	width: 64px;
+	height: 64px;
+	margin-right: 16px;
+}
+
+.userMInfoMetaRoot {
+	flex: 1;
+	overflow: hidden;
+}
+
+.userMInfoMetaName {
+	display: block;
+	width: 100%;
+	white-space: nowrap;
+	overflow: hidden;
+	text-overflow: ellipsis;
+}
+
+.userMInfoMetaSub {
+	display: block;
+	width: 100%;
+	font-size: 85%;
+	opacity: 0.7;
+	white-space: nowrap;
+	overflow: hidden;
+	text-overflow: ellipsis;
+}
+
+.userMInfoMetaState {
+	display: flex;
+	gap: 8px;
+	flex-wrap: wrap;
+	margin-top: 4px;
+
+	&:empty {
+		display: none;
+	}
+
+	> .suspended,
+	> .silenced,
+	> .moderator {
+		display: inline-block;
+		border: solid 1px;
+		border-radius: 6px;
+		padding: 2px 6px;
+		font-size: 85%;
+	}
+
+	> .suspended {
+		color: var(--error);
+		border-color: var(--error);
+	}
+
+	> .silenced {
+		color: var(--warn);
+		border-color: var(--warn);
+	}
+
+	> .moderator {
+		color: var(--success);
+		border-color: var(--success);
+	}
+}
+</style>
diff --git a/packages/frontend/src/store.ts b/packages/frontend/src/store.ts
index 0af2648772..65a3b90b1d 100644
--- a/packages/frontend/src/store.ts
+++ b/packages/frontend/src/store.ts
@@ -330,6 +330,10 @@ export const defaultStore = markRaw(new Storage('base', {
 		where: 'device',
 		default: 'medium' as 'small' | 'medium' | 'large',
 	},
+	limitWidthOfReaction: {
+		where: 'device',
+		default: true,
+	},
 	forceShowAds: {
 		where: 'device',
 		default: false,