Repository source: docs/plans/php_forum_rewrite_answered_questions.md
PHP Forum Rewrite Answered Questions
Historical snapshot, not a current reference. This document captures the
project's answers to its own early planning questions, including a v2
route inventory (e.g. /api/pow_requirement, /api/call_llm) that predates
this codebase and no longer exists here. It's preserved for design context
on why decisions were made, not as an up-to-date route list — for that,
read the routing/controller code directly.
This document collects the questions that have already been answered for the PHP rewrite. These answers reflect the current project direction, the active rewrite spec, the migrated canonical specs under docs/specs/, the reduced parity inventory in v3, and the retained fixture tree under tests/fixtures/. Historical references to v2 are informational only and exist for design context, not as implementation authority.
Current Product Contract
What exact current routes, page states, and plain-text APIs define the "current product slice" that V1 must match?
Answer: The current user-visible route set in v2 is:
/, /account/key/, /instance/, /activity/, /compose/thread, /compose/reply, /threads/<thread-id>, /posts/<post-id>, /profiles/<profile-slug>, /user/<username>, /assets/..., /favicon.ico, /llms.txt.
The plain-text API surface is:
/api/, /api/list_index, /api/get_thread, /api/get_post, /api/get_profile, /api/get_username_claim_cta, /api/create_thread, /api/create_reply, /api/pow_requirement, /api/link_identity, /api/set_identity_hint, /api/call_llm.
Is there a canonical inventory of existing public routes, write routes, redirects, and RSS outputs?
Answer: Yes. For v3, the canonical route inventory is the local authority set described in this document plus docs/specs/php_forum_rewrite_spec_v1.md and docs/plans/php_forum_rewrite_trimmed_parity_suite_v1.md. RSS outputs currently exist for / with ?format=rss, /threads/<thread-id>?format=rss, and /activity/?view=<mode>&format=rss.
Which current behaviors are considered compatibility-critical versus acceptable to simplify in V1?
Answer: Compatibility-critical user-facing behaviors appear to be: indexed public reads for board/thread/post/profile surfaces; activity filters and RSS; browser-signing-based compose flows; username capture during key generation; account key page; and plain-text API availability. What looks more simplifiable is copy/layout phrasing, some feature-flagged affordances, and whether self-profile/account pages remain partly dynamic initially.
What is the authoritative reference implementation for behavior that is not yet captured in
docs/specs/?
Answer: v3 should not depend on ~/v2 as the authority. The authority set is now:
docs/specs/php_forum_rewrite_spec_v1.md,
docs/specs/canonical_post_record_v1.md,
docs/specs/identity_bootstrap_record_v1.md,
docs/specs/profile_read_contract_v1.md,
docs/specs/public_key_storage_v1.md,
docs/plans/php_forum_rewrite_trimmed_parity_suite_v1.md,
and tests/fixtures/parity_minimal_v1/.
If those documents are still silent on a behavior, that behavior needs an explicit product decision before implementation.
What exact current-product behavior is in scope for parity where
v2behavior and the rewrite spec are still ambiguous?
Answer: Match the local v3 authority set only. If the local specs and plans are still ambiguous, make an explicit product decision in v3 rather than consulting v2 as a tie-breaker.
Canonical Record Definitions
Which exact record files and schemas under
records/are in scope for V1?
Answer: At minimum, V1 should carry forward the record families already present and used in v2 that remain in scope: records/posts/, records/identity/, records/public-keys/, and records/instance/.
Are there already versioned spec documents for every required canonical record family, or do some formats still live only in code/current behavior?
Answer: The retained canonical families are now spec-backed inside v3: rewrite spec, post records, identity bootstrap records, and public-key storage. Practical rule: do not implement or extend a canonical record family unless its behavior is versioned under docs/specs/.
Which exact
docs/specs/*.mdfiles are authoritative for each in-scope record family?
Answer: The authoritative in-scope spec files are:
docs/specs/php_forum_rewrite_spec_v1.md,
docs/specs/canonical_post_record_v1.md,
docs/specs/identity_bootstrap_record_v1.md,
docs/specs/profile_read_contract_v1.md,
and docs/specs/public_key_storage_v1.md.
Which in-scope record families still require a formal versioned spec before implementation starts?
Answer: None for the retained V1 scope. Posts, identity bootstrap, profile reads, and public-key storage are all covered by versioned local specs.
What canonical identity/bootstrap records are required for the system to function?
Answer: The current implementation clearly depends on identity bootstrap records under records/identity/ and canonical public keys under records/public-keys/. Identity-aware reads and browser-signing/bootstrap behavior depend on those identity records.
Are any canonical format changes acceptable for V1, or must the rewrite be fully backward-compatible with the existing repository layout and file contents?
Answer: Backward compatibility should be the default. For a budget-host migration, the cheapest and safest path is to preserve the existing repository layout and canonical record contents exactly and evolve only the derived read model and serving path.
Are there edge cases around ASCII enforcement, detached signatures, or path naming that need to be preserved exactly?
Answer: Yes. v2 treats ASCII-only canonical text as a product rule, detached-signature/public-key handling as part of the write contract, and record-family path layout as part of the application contract. Preserve ASCII, LF/trailing-LF, and existing directory-family boundaries exactly in V1 unless a later spec explicitly changes them.
Read-Model Design
Should V1 use one SQLite database or two?
Answer: Use two SQLite databases from the start: one for canonical-derived indexed state and one for route/view payloads or snapshots. This sits alongside filesystem _static_html/ artifacts, which remain the primary direct-serve path for static-safe anonymous reads.
What exact data must be materialized for posts, threads, profiles, and activity items?
Answer: Enough to render hot routes without reparsing records or reconstructing git history. At minimum:
posts with body/timestamps/author/root/parent; threads with root metadata/reply counts/last activity/tags/type; profiles with identity/current visible username/linked-identity summary/post summary/public-key summary; and activity items preclassified as content or code.
What is the required freshness model for incremental refresh after writes?
Answer: Successful writes should update affected indexed rows and then invalidate targeted _static_html/.../index.html artifacts and related route/view payloads. V1 should not eagerly regenerate all affected HTML after writes; the default strategy is targeted invalidation plus next-read regeneration.
Which routes should be lazily regenerated on the next safe read after invalidation?
Answer: All public HTML routes should regenerate lazily by default, including /, thread pages, post permalinks, profiles, /instance/, and activity pages.
On startup with a stale or missing read model, should the app block and rebuild, or serve a maintenance response while rebuilding?
Answer: Follow the v2 pattern: serve a clear lightweight refresh/rebuild interstitial for the first request, with an explicit rebuild path, then materialize the fresh page. That is better aligned with a budget host than globally blocking all requests.
What operator-visible signals are mandatory for rebuild state, stale state, and recovery events?
Answer: Keep these mandatory: read-model stale/missing status, rebuild started/completed/failed, current repo HEAD associated with the read model, schema/version mismatch, and route source headers or logs showing static-html, php-native, php-microcache, or dynamic fallback.
Activity and Project Info
What precisely belongs in the
codeactivity feed?
Answer: In v2, the code feed contains non-record repository commits such as application or docs changes. It excludes canonical content commits. The tests show code activity including paths like docs/notes.md and linking to the underlying git commit, while excluding content commits like post/reply creation.
What data source should power activity items that are currently derived from git history or repo facts?
Answer: In v2, activity is still fundamentally git-derived. Content and code activity come from git commit history. /instance/ also shows lightweight repo facts such as the current commit and the published instance record at records/instance/public.txt.
Recommendation for V1: keep git and canonical records as the offline source of truth, but index activity rows into SQLite for /activity/ and RSS so hot requests do not reconstruct git history on demand.
What are the exact filter, pagination, and RSS contracts that must remain stable?
Answer: Current activity filters are all, content, and code for V1 planning purposes. Default /activity/ behavior is effectively content. Pagination uses page=<n> with invalid or missing values normalized to page 1. RSS is available from /activity/?view=<mode>&format=rss. Board RSS is /?format=rss and thread RSS is /threads/<thread-id>?format=rss.
What content currently appears on
/instance/and which parts are mandatory for V1?
Answer: /instance/ currently shows:
public instance facts from records/instance/public.txt; a Project FAQ; a Facts section; a Project overview; the source file path (records/instance/public.txt); and current git commit information. The FAQ content includes explanations like why posts are ASCII-only, why OpenPGP is used, why text files and git are used, why the project should be forkable, and a contrast with a generic social feed.
Profiles, Identity, and Account Semantics
What exact profile fields are required now that profile updates are out of scope?
Answer: The visible profile model for V1 should include identity ID, current visible username, post history summary, public key material, and basic technical details. Separate post-bootstrap profile editing is out of scope. The username should be captured once during browser keypair generation and otherwise treated as fixed for V1.
How do public profile state and self-profile/account state differ today?
Answer: Public profile pages show the published profile and post history. Self-profile is triggered by ?self=1 and changes the nav state to My profile; it can show an empty-state page for unpublished identities and account-setup affordances. Unknown public profiles return 404, but unknown self-marked profiles render the "Your profile is ready to start" empty state.
What cookie semantics, identity hints, and browser-held key flows must be preserved exactly?
Answer: v2 has an identity-hint mechanism using the forum_identity_hint cookie plus /api/set_identity_hint. Browser-held OpenPGP keys are central to the compose and account flows: the browser can generate or import a key, sign payloads client-side, and view key material on /account/key/. For V1, generated-key bootstrap should ask for a username via standard prompt() and fall back to guest when prompt() is unavailable or unusable. The profile/account nav JS also depends on identity-hint-aware enhancement behavior.
What are the failure modes for signature verification, and what user-visible error contracts must they produce?
Answer: User-visible failures currently come back as deterministic text/plain API errors with stable status codes such as 400 Bad Request for malformed or invalid payloads and 403 Forbidden for policy failures. Signature verification failures, invalid usernames, and missing proof-of-work all surface this way.
Write Paths and Policy
What are the exact request/response contracts for:
create thread
create reply
username/account flows
Answer: The signed write APIs all use POSTs. The main JSON request shape in v2 is payload, signature, public_key, and dry_run; unsigned fallback can omit signature/public key when that feature flag is enabled. Success responses are deterministic text/plain bodies that echo key record metadata and include commit information. The specific endpoints still relevant to V1 are:
/api/create_thread, /api/create_reply, /api/link_identity.
Which current
v2write flows count as the "most important write/account flows" for V1 acceptance?
Answer: Create thread, create reply, and username capture during key generation are the hard requirement.
What validations are required before canonical record materialization for each write type?
Answer: Current functional requirements include payload parsing, detached-signature verification for signed flows, username-shape validation during identity bootstrap, and proof-of-work validation for first-post flows when the POW feature is enabled.
Are writes always synchronous from the user's perspective, or are any slow operations allowed to complete out of band?
Answer: The current product contract is synchronous immediate read-after-write for core flows. Successful API writes return only after the canonical record is stored, git-committed, and the relevant read model refresh has run.
What should happen if git commit succeeds but incremental read-model refresh fails?
Answer: Treat the write as canonically successful, mark derived state stale, remove affected static HTML artifacts, and force deterministic recovery on the next read or startup. Do not roll back the git commit; git remains canonical.
What operator tooling is expected for inspecting or recovering partially failed write flows?
Answer: Minimum required tooling: visible stale/read-model status, recent write operation log with timing and failure step, deterministic rebuild commands/paths for indexed state, deterministic static-artifact purge/regenerate commands/paths, and a way to inspect recent write/rebuild failures and current repo HEAD.
Routing, Rendering, and Assets
Which existing URLs must remain byte-for-byte compatible, and which may redirect?
Answer: The safest compatibility set is the route list documented above, especially /, /threads/<id>, /posts/<id>, /instance/, /activity/, /profiles/<slug>, /user/<username>, compose pages, the plain-text /api/... endpoints, /assets/..., /favicon.ico, and /llms.txt.
Are there any known SEO, bookmark, or external-link dependencies on current route shapes?
Answer: The product clearly expects stable bookmarks and direct links for thread pages, post permalinks, username pages, profile pages, and activity filters. RSS links are embedded in board/thread/activity pages, so those route shapes are also externally consumable.
What shared templates, CSS contracts, and enhancement assets already exist and must be preserved or ported?
Answer: v2 has a shared page shell, shared primary nav, shared profile-nav contract, and shared asset routes. Important in-scope assets include site.css, primary_nav.js, profile_nav.js, browser_signing.js, copy_field.js, profile_key_viewer.js, account_key_actions.js, and the favicon assets.
Are assets definitely PHP-served in V1, or can some static serving remain outside PHP if the route contract stays stable?
Answer: Static serving should remain outside PHP whenever possible. For maximum throughput on a budget host: Apache should serve immutable/versioned assets directly, Apache should serve prebuilt _static_html/.../index.html files directly for allowlisted HTML routes, and PHP should only handle dynamic fallback, personalized/uncacheable requests, writes, and routes with no current artifact.
What does
llms.txtneed to contain, and is it generated or static?
Answer: In v2, /llms.txt is a text route generated by the app. It documents machine-readable and posting surfaces including at least GET /api/, POST /api/create_thread, GET /compose/thread, and guidance to use /instance/ for public operator/deployment facts.
Caching and Performance
What TTLs should be used for the route microcache on each eligible route family?
Answer: Keep the PHP microcache short, around the existing v2 value of 5 seconds, and treat it as a fallback layer rather than the main throughput path. Static HTML bypass should carry most anonymous read traffic.
Which query-string variants, if any, are safe to cache?
Answer: For direct static HTML bypass, only queryless GETs should be eligible. For PHP fallback and the route/view payload database, V1 should keep query-bearing variants fully dynamic rather than introducing a fixed snapshot allowlist.
What invalidation granularity is required after each write type?
Answer: Prefer targeted invalidation over blanket clears. Minimum route-family targeting:
create thread: /, affected board listings if materialized, new thread page, new post permalink, and author profile.
create reply: thread page, reply permalink, board index if last-activity ordering changes, and author profile.
identity bootstrap / username capture: profile page, username route, and any surfaces showing the initial username for that identity.
If targeted logic is too complex early on, clearing only the affected subtree under _static_html/ and corresponding route/view payloads is acceptable; full-tree clears should be the fallback of last resort.
What measurable performance baseline from the current stack should the rewrite beat?
Answer: The rewrite should beat the current dynamic Python/PHP bridge for anonymous hot reads by serving prebuilt static HTML without PHP execution on the steady-state happy path, by avoiding request-time full repository parses, and by avoiding request-time git-log reconstruction for activity.
What named timing steps or logs are required for hotspot analysis?
Answer: Keep timing around static HTML hit/miss, PHP-native payload hit/miss, PHP microcache hit/miss, CGI/dynamic fallback duration, read-model refresh duration, and write-path substeps such as parse, verify, validate, git add, git commit, rev-parse, refresh, and static invalidation.
Deployment and Operations
What PHP runtime and extensions are available in production?
Answer: Assume a conservative shared-host PHP setup with standard filesystem functions, JSON, SQLite/PDO SQLite, and .htaccess with mod_rewrite. Avoid unusual dependencies.
Implementation note: v3 should carry a checked-in public/.htaccess that serves existing files/directories first, serves sibling route .html artifacts directly when present, and falls back to public/index.php otherwise.
What deployment model will own startup rebuilds, permissions, and writable cache/state directories?
Answer: Use a single checked-out repo plus writable sibling/state directories owned by the web user. Required writable areas are derived SQLite/index state, _static_html/, PHP microcache directory, and canonical records/ families that accept writes. Startup rebuilds should be request-driven and deterministic rather than daemon-driven.
How is the repository checked out in production, and can PHP safely run the required git commands there?
Answer: The intended model remains a writable on-disk checkout where the application can read and write canonical files and invoke non-interactive git commands. PHP should orchestrate non-interactive git usage carefully and avoid shell interpolation.
Are there concurrency constraints for simultaneous writes or rebuilds on a single instance?
Answer: Yes. Assume single-instance, low-write concurrency and serialize writes/rebuilds with a simple lock. That matches both the product and the host profile.
What backup, rollback, or recovery procedure is expected during cutover?
Answer: Treat this as a greenfield project rather than a production cutover. Lean on git plus rebuildable derived state: back up the repo checkout and config, treat SQLite and _static_html/ as disposable derived artifacts, and rebuild derived state from repo HEAD instead of restoring caches.
Testing and Acceptance
What existing automated tests or fixtures can be reused as a regression oracle?
Answer: Inside v3, the reduced parity oracle is defined by docs/plans/php_forum_rewrite_trimmed_parity_suite_v1.md plus tests/fixtures/parity_minimal_v1/. Historical v2 tests may inspire design ideas, but they are not required for implementation and are not part of the authority set.
Is there an accepted fixture repository or golden-output set for route parity testing?
Answer: Yes for the reduced retained scope: tests/fixtures/parity_minimal_v1/ is the seed fixture tree in v3. It is intentionally small and should be expanded only for in-scope route parity needs.
Which browser-level behaviors must be manually verified in addition to request tests?
Answer: Browser-signing flows, account key generation/import/viewing, primary-nav enhancement, profile-nav enhancement, key-generation username prompt behavior, fallback-to-guest behavior, and identity-hint cookie interactions should all be manually smoke-tested even if server request tests pass.
What is the acceptance bar for "feature-complete relative to the current product slice"?
Answer: At minimum, V1 should reproduce the current tested read behavior and the observable contracts for the most important write flows: public reads, compose flows, signed thread/reply writes, username/bootstrap behavior, activity/RSS, and the plain-text API surfaces documented above.
Who signs off on parity for activity, profiles, account/key-bootstrap flows, and operational tooling?
Answer: One repo owner or product maintainer signs off on all parity areas.