فهرست مقاله
فرض کنید چند رویدادِ یک آزمایشِ نرمافزاری را بهترتیب ذخیره کردهایم و بعد نسخهای از همان گزارش به ما میرسد. مقایسهٔ یک چکیدهٔ نهایی فقط وقتی معنای تاریخی دارد که مرجعِ مقایسه همراهِ نسخهٔ موردِ پرسش عوض نشود. این درس یک زنجیرهٔ کوچک و کاملاً ساختگی از بایتها میسازد تا تفاوتِ سازگاریِ درونی و تطبیق با مرجعِ پذیرفتهشده روشن شود. فایل، گزارشِ واقعی را نمیخواند، چیزی را روی سرویس نمینویسد و منبعِ قابلاعتماد برای لنگر ایجاد نمیکند.
تعریفِ دنباله و مرزِ اعتماد

هر رویداد در رابطِ ما یک bytes دقیق است. دنباله باید تاپلِ صفر تا هشت رویداد باشد و هر رویداد حداکثر بیستوچهار بایت داشته باشد. رویدادِ تهی مجاز است؛ نبودنِ رویداد با یک رویدادِ دارای محتوای تهی فرق دارد. این سقفها قراردادِ آموزشیِ خودمان هستند و محدودیتِ عمومیِ SHA256 یا کتابخانهٔ پایتون معرفی نمیشوند.
لنگرِ پذیرفتهشده دو جزء دارد: تعدادِ رویدادها و چکیدهٔ انتهاییِ سیودوبایتی. تابعِ verify_anchor آنها را از فراخواننده میگیرد. اگر فراخواننده همین دو مقدار را از نسخهٔ مشکوک حساب کند و فوراً «مرجع» بنامد، تنها محاسبهای سازگار ساخته است. در آزمایش، لنگرِ نسخهٔ اصلی را پیش از تولیدِ نسخههای تغییرکرده نگه میداریم؛ کانالِ بیرونیِ مطمئن، امضا یا نگهداریِ امنِ لنگر پیاده نشده است.
در درسِ HMAC و بایتهای پیام، رابطهٔ یک پیام با کلیدِ مشترک بررسی میشد. اینجا کلید نداریم و دربارهٔ فرستنده احرازِ هویت انجام نمیدهیم. درسِ عضویتِ مرتب در مرکل هم شاهدِ یک جایگاه در درختِ ثابت میساخت؛ کدِ حاضر کلِ دنبالهٔ کوچک را دوباره محاسبه میکند و شاهدِ عضویتِ کوتاه تولید نمیکند.
قاببندیِ بدون ابهام برای بایتهای هر رویداد

حالتِ آغازین، چکیدهٔ پیامِ ثابتِ event-log/v1، بایتِ صفر و واژهٔ genesis است. برای هر رویداد، پیامِ گره از پیشوندِ جداگانهٔ node، چکیدهٔ قبلی، شمارهٔ صفرمبنا، طولِ رویداد و بایتهای خودِ رویداد ساخته میشود. رشتههای ثابت و ترتیبِ این بخشها انتخابِ این مثالاند؛ قالبِ استانداردِ ثبتِ رویداد یا پیادهسازیِ پروتکلِ دیگری ادعا نمیشود.
شماره و طول با struct.pack('>II', ...) نوشته میشوند: دو عددِ صحیحِ بدونِ علامت، هرکدام چهار بایت، با ترتیبِ بزرگانتها و بدون همترازیِ بومی. مستنداتِ struct معنیِ پیشوند و اندازهها را مشخص میکند. برای شمارهٔ دو و طولِ سه، هشت بایتِ سربرگ در نمایشِ هگز 0000000200000003 هستند؛ خودِ نویسههای هگز وارد هش نمیشوند.
مثالِ ابهام دربارهٔ چسباندنِ سادهٔ چند رویدادِ با طولِ متغیر است: دو دنبالهٔ (ab, c) و (a, bc) هر دو بایتهای abc میدهند. نباید از این مثال نتیجه گرفت که «چکیدهٔ ثابتِ سیودوبایتی بهعلاوهٔ تنها یک محتوای انتهایی» ذاتاً مرزِ نامعلوم دارد؛ آن مرز از طولِ ثابت معلوم است. شماره، طول و پیشوند در اینجا قالبِ انتخابیِ روشن و قابلبازبینیِ ما را تعریف میکنند.
ساختِ زنجیره و وارسیِ ترتیب

مسیرِ اصلی، اجزای پیامِ هر گره را با فراخوانیهای جداگانهٔ update وارد SHA256 میکند. طبقِ مستنداتِ Hash Objects، این کار با هشکردنِ اتصالِ همان اجزا برابر است. digest بایتِ چکیده را میدهد؛ hexdigest فقط نمایشِ متنی است. دنبالهٔ برگشتی، حالتِ آغازین و سپس یک چکیده برای هر رویداد دارد.
نمونهٔ اصلی سه رویدادِ boot، limit=7 و halt دارد. چهار حالتِ چکیده، در خروجی چاپ میشوند. تغییرِ هفت به نه، بدونِ تغییرِ تعداد یا طولِ همان رویداد، با لنگرِ اصلی نمیگذرد. جابهجاییِ دو رویداد نیز در همین شاهد رد میشود؛ مجموعهٔ بایتها ثابت مانده، ولی ترتیبِ دنباله عوض شده است.
پیش از محاسبه، تمامِ رویدادها و شکلِ لنگر بررسی میشوند. بولی بهجای تعداد پذیرفته نیست؛ bytearray، نمای حافظه، زیرکلاسها و رشتهٔ هگز نیز بیصدا تبدیل نمیشوند. این سختگیری متعلق به رابطِ ماست. شکلِ نامعتبر خطا میدهد، اما دنباله و لنگرِ دارای شکلِ درست که با هم تطبیق ندارند، نتیجهٔ False دارند.
لنگرِ مستقل و بریدنِ انتهای گزارش

نسخهای که تنها رویدادِ آخرش حذف شده، پیشوندِ واقعیِ زنجیرهٔ اصلی است. چکیدههای باقیمانده با هم سازگارند و تابعِ locally_consistent آن را میپذیرد. بااینحال، تعداد و انتهای آن با لنگرِ اصلی برابر نیست. این شاهد نشان میدهد که سازگاریِ محاسباتیِ یک پیشوند، بهتنهایی گواهِ کاملبودنِ گزارشِ دریافتشده نیست.
بازنویسیِ محتوا و محاسبهٔ دوبارهٔ همهٔ چکیدهها نیز یک زنجیرهٔ درونیِ سازگار میدهد. اگر لنگرِ تازهٔ همان نسخه پذیرفته شود، وارسیِ آن میگذرد؛ اگر مرجعِ اصلی ثابت بماند، نمونهٔ بازنویسیشدهٔ ما رد میشود. حتی مرجعِ معتبر هم رویدادی را که از ابتدا ثبت نشده تشخیص نمیدهد. این برنامه دربارهٔ همهٔ اتفاقهای دنیای واقعی، زمانِ ثبت یا تازهترین نسخه تضمین نمیدهد.
کدِ کامل را با نامِ event_log_hash_chain.py ذخیره کنید. اجرای همراه فقط کتابخانهٔ استانداردِ پایتون دارد و خروجیِ JSON را با پایانِ خطِ مشخص مینویسد. در این فایل، مسیرِ اصلی و مرجع هر دو از SHA256 کتابخانه استفاده میکنند؛ آزمونِ حاضر پیادهسازیِ مستقلِ تابعِ رمزنگاری یا ارزیابیِ سرعت نیست.
"""Bounded event-chain model, not authentication or a real append-only service."""
from hashlib import sha256
from itertools import product
import json
import platform
import struct
import sys
MAX_EVENTS = 8
MAX_EVENT_BYTES = 24
GENESIS_MESSAGE = b'event-log/v1\x00genesis'
NODE_DOMAIN = b'event-log/v1\x00node'
def checked_events(events):
if type(events) is not tuple:
raise TypeError('events must be an exact tuple')
if len(events) > MAX_EVENTS:
raise ValueError('at most eight events')
for event in events:
if type(event) is not bytes:
raise TypeError('each event must be exact bytes')
if len(event) > MAX_EVENT_BYTES:
raise ValueError('at most 24 bytes per event')
return events
def checked_anchor(count, tail):
if type(count) is not int:
raise TypeError('accepted count must be an exact int, not bool')
if not 0 <= count <= MAX_EVENTS:
raise ValueError('accepted count outside the own profile')
if type(tail) is not bytes:
raise TypeError('accepted tail must be exact bytes')
if len(tail) != 32:
raise ValueError('accepted tail must have 32 bytes')
def _step(previous, position, payload):
# Chosen format, not a claim that a fixed digest + one payload needs a length.
h = sha256()
h.update(NODE_DOMAIN)
h.update(previous)
h.update(struct.pack('>II', position, len(payload)))
h.update(payload)
return h.digest()
def _chain_checked(events):
trail = [sha256(GENESIS_MESSAGE).digest()]
for position, payload in enumerate(events):
trail.append(_step(trail[-1], position, payload))
return tuple(trail)
def build_chain(events):
"""Return immutable genesis + one digest per event; validate everything first."""
return _chain_checked(checked_events(events))
def verify_anchor(events, accepted_count, accepted_tail):
"""The accepted pair must be supplied independently of the candidate.
This checks only the exact finite byte format. It does not establish that
the anchor is authentic, that every real event was recorded, or that this
is the latest allowed history. A malformed contract raises, a mismatch is False.
"""
events = checked_events(events)
checked_anchor(accepted_count, accepted_tail)
if len(events) != accepted_count:
return False
return _chain_checked(events)[-1] == accepted_tail
def locally_consistent(events, supplied_trail):
"""Recomputable internal consistency only; no independent accepted anchor."""
events = checked_events(events)
if type(supplied_trail) is not tuple:
raise TypeError('supplied trail must be an exact tuple')
if len(supplied_trail) > MAX_EVENTS + 1:
raise ValueError('trail exceeds the own profile')
for digest in supplied_trail:
if type(digest) is not bytes:
raise TypeError('each claimed digest must be exact bytes')
if len(digest) != 32:
raise ValueError('each claimed digest must have 32 bytes')
return supplied_trail == _chain_checked(events)
def manual_unsigned32(value):
# Test-only encoder: no struct, to_bytes, main framing, or main validators.
return bytes((value >> shift) & 255 for shift in (24, 16, 8, 0))
def whole_message_reference(events):
"""Independent serialization/one-shot reference; the SHA256 primitive is shared."""
previous = sha256(b'event-log/v1\x00genesis').digest()
trail = [previous]
for position in range(len(events)):
payload = events[position]
message = (b'event-log/v1\x00node' + previous
+ manual_unsigned32(position)
+ manual_unsigned32(len(payload)) + payload)
previous = sha256(message).digest()
trail.append(previous)
return tuple(trail)
def rejects(call):
try:
call()
except (TypeError, ValueError):
return True
return False
def self_check():
original = (b'boot', b'limit=7', b'halt')
trail = build_chain(original)
# The test chooses an original version before producing altered candidates.
# No authentic external checkpoint service is implemented here.
accepted_count, accepted_tail = len(original), trail[-1]
edited = (b'boot', b'limit=9', b'halt')
reordered = (original[1], original[0], original[2])
missing_middle = (original[0], original[2])
truncated = original[:-1]
appended = original + (b'after',)
checks = {}
published_message = b'Nobody inspects the spammish repetition'
published_digest = '031edd7d41651593c5fe5c006fa5752b37fddff7bc4e843aa6af0c950f4b9406'
checks['attributed_hashlib_usage_known_digest'] = (
sha256(published_message).hexdigest() == published_digest)
previous = bytes(range(32))
manual_message = (b'event-log/v1\x00node' + previous
+ b'\x00\x00\x00\x02\x00\x00\x00\x03' + b'abc')
checks['manual_index_length_bytes_and_streamed_message'] = (
struct.pack('>II', 2, 3).hex() == '0000000200000003'
and manual_unsigned32(2) + manual_unsigned32(3) == struct.pack('>II', 2, 3)
and _step(previous, 2, b'abc') == sha256(manual_message).digest()
and len(manual_message) == 60)
checks['zero_events_and_one_empty_event_have_distinct_anchors'] = (
len(build_chain(())) == 1 and len(build_chain((b'',))) == 2
and build_chain(())[-1] != build_chain((b'',))[-1]
and verify_anchor((), 0, build_chain(())[-1]) is True
and verify_anchor((b'',), 0, build_chain(())[-1]) is False)
checks['independently_supplied_pair_accepts_original_without_mutation'] = (
verify_anchor(original, accepted_count, accepted_tail) is True
and original == (b'boot', b'limit=7', b'halt')
and trail == whole_message_reference(original))
checks['same_count_same_length_payload_edit_is_rejected'] = (
len(edited) == len(original) and len(edited[1]) == len(original[1])
and verify_anchor(edited, accepted_count, accepted_tail) is False)
checks['event_order_change_with_same_payload_multiset_is_rejected'] = (
sorted(reordered) == sorted(original) and reordered != original
and verify_anchor(reordered, accepted_count, accepted_tail) is False)
checks['interior_deletion_is_not_accepted_by_original_pair'] = (
locally_consistent(missing_middle, build_chain(missing_middle)) is True
and verify_anchor(missing_middle, accepted_count, accepted_tail) is False)
checks['prefix_truncation_and_extension_need_the_original_anchor'] = (
build_chain(truncated) == trail[:-1]
and locally_consistent(truncated, trail[:-1]) is True
and verify_anchor(truncated, accepted_count, accepted_tail) is False
and verify_anchor(appended, accepted_count, accepted_tail) is False)
checks['rewritten_history_and_replaced_anchor_are_self_consistent_only'] = (
locally_consistent(edited, build_chain(edited)) is True
and verify_anchor(edited, len(edited), build_chain(edited)[-1]) is True
and verify_anchor(edited, accepted_count, accepted_tail) is False)
a, b = (b'ab', b'c'), (b'a', b'bc')
checks['naive_whole_log_concatenation_is_not_our_framed_sequence'] = (
b''.join(a) == b''.join(b) == b'abc' and a != b
and build_chain(a)[-1] != build_chain(b)[-1])
class TupleChild(tuple):
pass
class BytesChild(bytes):
pass
class IntChild(int):
pass
invalid_logs = [[], None, b'A', True, TupleChild(()), (b'A',) * 9]
invalid_payloads = [None, 'A', 1, True, bytearray(b'A'), memoryview(b'A'),
BytesChild(b'A'), b'A' * 25]
consumed = []
def lazy():
consumed.append('consumed')
yield b'A'
generator = lazy()
checks['complete_log_validation_and_generator_nonconsumption'] = (
all(rejects(lambda v=v: build_chain(v)) for v in invalid_logs)
and all(rejects(lambda v=v: build_chain((b'valid first', v)))
for v in invalid_payloads)
and rejects(lambda: build_chain(generator)) and consumed == [])
invalid_counts = [-1, 9, True, 1.0, IntChild(3), None]
invalid_tails = ['0' * 64, b'', b'x' * 31, b'x' * 33,
bytearray(32), memoryview(bytes(32)), BytesChild(bytes(32))]
invalid_claims = [list(trail), (b'short',), (accepted_tail,) * 10]
checks['anchor_and_claim_digest_contracts_are_strict_ONE_group'] = (
all(rejects(lambda v=v: verify_anchor(original, v, accepted_tail))
for v in invalid_counts)
and all(rejects(lambda v=v: verify_anchor(original, accepted_count, v))
for v in invalid_tails)
and all(rejects(lambda v=v: locally_consistent(original, v))
for v in invalid_claims))
profiles = states = mutations = 0
oracle_ok = True
alphabet = (b'', b'a', b'bc', b'\x00')
for size in range(5):
for events in product(alphabet, repeat=size):
expected = whole_message_reference(events)
actual = build_chain(events)
oracle_ok &= actual == expected
oracle_ok &= verify_anchor(events, size, expected[-1]) is True
oracle_ok &= locally_consistent(events, expected) is True
states += len(expected)
variants = [events + (b'x',)]
if events:
variants.extend(((events[0] + b'!',) + events[1:], events[:-1]))
if size >= 2 and events[0] != events[1]:
variants.append((events[1], events[0]) + events[2:])
for changed in variants:
oracle_ok &= build_chain(changed) == whole_message_reference(changed)
oracle_ok &= verify_anchor(changed, size, expected[-1]) is False
mutations += 1
profiles += 1
checks['bounded_341_profiles_and_mutations_match_ONE_reference_group'] = bool(
oracle_ok and profiles == 341 and states == 1593 and mutations == 1273)
cap = tuple(bytes([i]) * MAX_EVENT_BYTES for i in range(MAX_EVENTS))
first, second = build_chain(cap), build_chain(cap)
checks['caps_immutable_fresh_state_and_exact_claim_length'] = (
len(first) == 9 and all(type(x) is bytes and len(x) == 32 for x in first)
and first == second == whole_message_reference(cap) and first is not second
and type(first) is tuple and locally_consistent(cap, first[1:]) is False
and verify_anchor(cap, 8, first[-1]) is True)
assert len(checks) == 14 and all(type(v) is bool for v in checks.values())
assert all(checks.values()), checks
return dict(
python=platform.python_version(), dependencies='standard library only',
scope='Own bounded bytes chain and independently accepted pair; no real log, authentication, secure checkpoint service or cryptographic proof',
format=dict(max_events=8, max_event_bytes=24, digest_bytes=32,
index_and_length_header_bytes=8,
genesis_message_hex=GENESIS_MESSAGE.hex(), node_domain_hex=NODE_DOMAIN.hex()),
fixture=dict(events_ascii=[v.decode('ascii') for v in original],
accepted_count=accepted_count, accepted_tail_hex=accepted_tail.hex(),
prefix_tails_hex=[v.hex() for v in trail], original_accepted=True,
edited_accepted=False, reordered_accepted=False,
interior_deleted_accepted=False, truncated_accepted=False,
appended_accepted=False),
unanchored_counterexample=dict(truncated_count=len(truncated),
truncated_trail_is_original_prefix=True, truncated_local_consistency=True,
rewritten_local_consistency=True, rewritten_with_replaced_pair_accepted=True,
rewritten_with_original_pair_accepted=False),
framing_counterexample=dict(first_events_hex=[v.hex() for v in a],
second_events_hex=[v.hex() for v in b], same_naive_concat_hex=b''.join(a).hex(),
different_framed_tail=True,
framing_scope='Multiple variable-length events; fixed32byte predecessor plus one trailing payload is already separable.'),
oracle_profiles_inside_ONE_group=profiles, oracle_state_comparisons=states,
oracle_mutated_candidate_comparisons=mutations,
invalid_input_cases=(len(invalid_logs) + len(invalid_payloads) + 1
+ len(invalid_counts) + len(invalid_tails) + len(invalid_claims)),
SHA256_primitive_shared_with_reference=True,
authentication_or_realworld_completeness_established=False,
unique_executed_checks=len(checks), checks=checks, all_passed=all(checks.values()))
if __name__ == '__main__':
sys.stdout.buffer.write((json.dumps(self_check(), ensure_ascii=True, indent=2)
+ '\n').encode('ascii'))
{
"python": "3.14.5",
"dependencies": "standard library only",
"scope": "Own bounded bytes chain and independently accepted pair; no real log, authentication, secure checkpoint service or cryptographic proof",
"format": {
"max_events": 8,
"max_event_bytes": 24,
"digest_bytes": 32,
"index_and_length_header_bytes": 8,
"genesis_message_hex": "6576656e742d6c6f672f76310067656e65736973",
"node_domain_hex": "6576656e742d6c6f672f7631006e6f6465"
},
"fixture": {
"events_ascii": [
"boot",
"limit=7",
"halt"
],
"accepted_count": 3,
"accepted_tail_hex": "811954033a13ff23f445362333b890cc8be305ddf5837a12abcc6f2ef292261d",
"prefix_tails_hex": [
"0a3d6e9cda3a37f4012d9cb0cf6e809e366692861ffb63c79cb609afdcb4185f",
"5267c6d5ffffe4a8c6683f5a029a3745a510ae6ab2f64eb819f6f5cacbb1cf5e",
"a3bfc9cc8d9a50b2e634e146f7ced9114f8efeefd2d2beae948e4b73dd9bd708",
"811954033a13ff23f445362333b890cc8be305ddf5837a12abcc6f2ef292261d"
],
"original_accepted": true,
"edited_accepted": false,
"reordered_accepted": false,
"interior_deleted_accepted": false,
"truncated_accepted": false,
"appended_accepted": false
},
"unanchored_counterexample": {
"truncated_count": 2,
"truncated_trail_is_original_prefix": true,
"truncated_local_consistency": true,
"rewritten_local_consistency": true,
"rewritten_with_replaced_pair_accepted": true,
"rewritten_with_original_pair_accepted": false
},
"framing_counterexample": {
"first_events_hex": [
"6162",
"63"
],
"second_events_hex": [
"61",
"6263"
],
"same_naive_concat_hex": "616263",
"different_framed_tail": true,
"framing_scope": "Multiple variable-length events; fixed32byte predecessor plus one trailing payload is already separable."
},
"oracle_profiles_inside_ONE_group": 341,
"oracle_state_comparisons": 1593,
"oracle_mutated_candidate_comparisons": 1273,
"invalid_input_cases": 31,
"SHA256_primitive_shared_with_reference": true,
"authentication_or_realworld_completeness_established": false,
"unique_executed_checks": 14,
"checks": {
"attributed_hashlib_usage_known_digest": true,
"manual_index_length_bytes_and_streamed_message": true,
"zero_events_and_one_empty_event_have_distinct_anchors": true,
"independently_supplied_pair_accepts_original_without_mutation": true,
"same_count_same_length_payload_edit_is_rejected": true,
"event_order_change_with_same_payload_multiset_is_rejected": true,
"interior_deletion_is_not_accepted_by_original_pair": true,
"prefix_truncation_and_extension_need_the_original_anchor": true,
"rewritten_history_and_replaced_anchor_are_self_consistent_only": true,
"naive_whole_log_concatenation_is_not_our_framed_sequence": true,
"complete_log_validation_and_generator_nonconsumption": true,
"anchor_and_claim_digest_contracts_are_strict_ONE_group": true,
"bounded_341_profiles_and_mutations_match_ONE_reference_group": true,
"caps_immutable_fresh_state_and_exact_claim_length": true
},
"all_passed": true
}
آزمونهای محدود، پاسخِ تمرینها و مرزِ نتیجه

چهارده گروهِ نامدار، شاهدِ دستیِ قالب، ویرایش، ترتیب، حذف، طول، نوع و مرزِ اعتماد را بررسی میکنند. خانوادهٔ محدود، سیصد و چهلویک تاپل با طولِ صفر تا چهار را از چهار محتوای بایتی میسازد. مرجع، عددها را با جابهجاییِ بیت و بایتگذاریِ دستی رمز میکند و کلِ پیام را یکباره هش میکند؛ از قاببندی یا تابعِ زنجیرهٔ اصلی استفاده نمیکند. همهٔ این خانواده، با مقایسههای تغییریافتهاش، یک گروه است.
بردارِ شناختهشدهٔ بخشِ Usage از مستنداتِ hashlib نیز با انتسابِ روشن بررسی میشود. آزمونهای موفق فقط رفتارِ این ورودیهای محدود را ثبت میکنند؛ از آنها ناممکنبودنِ برخورد یا ردِ هر دستکاریِ ممکن نتیجه نمیگیریم. تفسیرِ رمزنگاریِ لنگر، فرضهای جداگانهای دربارهٔ تابعِ هش و اعتماد به مرجع لازم دارد که این برنامه اثبات نمیکند.
پرسش اول: آیا رویدادِ تهی باید حذف شود؟ پاسخ: خیر؛ قرارداد آن را یک رویداد میداند، تعداد افزایش مییابد و یک گره افزوده میشود. فهرستِ تهی فقط حالتِ آغازین دارد. حذفِ تهیها تصمیمِ معناییِ دیگری است و این کد آن را انجام نمیدهد.
پرسش دوم: چرا داشتنِ تعداد در لنگر مفید است؟ پاسخ: نسخهٔ کوتاهشده، پیشوندی سازگار دارد ولی تعدادِ پذیرفتهشده را ندارد. زوجِ تعداد و انتها، مرجعِ موردِ انتظار را صریح میکند؛ این زوج باید مستقل داده شود، نه اینکه از همان نسخهٔ ورودی اعتبار بگیرد.
پرسش سوم: آیا زنجیرهٔ سازگار نویسنده را مشخص میکند؟ پاسخ: خیر؛ هیچ کلید یا امضایی نداریم و هرکس میتواند برای بایتهای دلخواهش چکیده حساب کند. پذیرشِ مرجع، هویت و مجوزِ نویسنده، مسئلهٔ دیگری است.
پرسش چهارم: اگر ترتیبِ رویدادهای واقعاً هممعنا عوض شود، باید پذیرفته شوند؟ پاسخ: این رابط چنین همارزیای تعریف نکرده است؛ دنبالهٔ مرتبِ بایتها را میسنجد. ترتیب، کدگذاریِ متن، نسخهٔ مجاز و سیاستِ نگهداری باید بیرون از این مدل مشخص شوند.
منابع در ۲۹ مهرِ ۱۴۰۵ خوانده شدند؛ عنوانِ صفحاتِ مرجع نسخهٔ 3.14.9 را نشان میدهد و نسخهٔ اجرای واقعی جدا در خروجی ثبت میشود. تاریخِ دسترسی را تاریخِ انتشار نمینامیم. دو مطلبِ مرتبط نیز از بدنههای کاملِ ذخیرهشده خوانده شدند؛ در زمانِ آمادهسازی، وارسیِ زندهٔ دوبارهٔ پیوندها و انتشار انجام نشده است.
منابع و مطالعهٔ بیشتر
بررسی منابع: ۲۹ مهر ۱۴۰۵. تحلیلها و پیشنهادهای اجرایی، جمعبندی نویسندهاند.

